티스토리 뷰

develop

3. Test code 작성 + DI

yogae 2020. 3. 3. 00:16

DI를 활용하여 test code를 작성하는 방법에 대하여 알아보자.

DI + test code

  class Robot {
      private helloService;
      constructor() {
          this.helloService = new HelloService();
      }

      public start() {
          return this.helloService.hello();
      }
  }

 

위와 같이 Robot class 안에 HelloService를 new하면 Robot은 HelloService에 종속하게 된다. Robot class의 test code를 작성하기 위해서는 HelloService의 hello mothod의 호출을 생각해야한다. 이러한 종속성을 제거하기 위해 inversify와 같은 DI container를 사용하여 class내부에서 객체의 생성을 방지하게 된다. DI container를 활용하여 test code를 작성할 때는 HelloService의 객체를 주입하기 전 테스트더블로 객체를 대체하게 된다.

테스트더블

실제 객체를 대체하는 방법을 테스트더블이라고 한다. 영화 촬용 시 위험한 역할을 대신하는 스턴트 더블에서 비롯된 이름이라고 한다. 테스트 더블에는 spy, stub, mock이 있다.

Spy

 spy는 호출 여부를 확인하기 위해 사용한다. 실제 호출이 이루어지며, 몇번 호출 했는지 무슨 parameters로 호출되었는지 등을 확인할 때 사용한다.

 

    describe('spy test', function () {
        let helloSpy: sinon.SinonSpy;
        before(function () {
            helloSpy = sinon.spy(helloService, 'hello'); // hello method를 spy
            robot = new Robot(helloService);
        });

        after(function () {
            sinon.restore();
        })

        it('test', function () {
            const name = 'yogae';
            const res = robot.start(name);
            chai.expect(res.startsWith('hello')).to.be.equal(true);
            chai.expect(helloSpy.calledOnce).to.be.equal(true); // hello method 한 번 호출 되었는지 확인

            const [argName] = helloSpy.getCall(0).args; // hello method parameter 값 확인
            chai.expect(argName).to.be.equal(name);
        });
    });

 

spy를 사용하여 helloService의 hello method가 한 번만 호출 되었는지 확인했고 hello method를 호출 할 때 parameter 값을 확인해보았다. stub나 mock과 다르게 spy는 hello method를 실행하게 된다.

Stub

실제 동작하는 것 처럼 객체를 만드는 것이다. 호출자를 실제 구현물로부터 격리시킬 목적으로 런타임에 실제 코드 대신 삽입되는 코드 조각이다.

 

    describe('stub test', function () {
        let helloStub: sinon.SinonStub;
        before(function () {
	    // hello method를 stub
            // hello method의 반환값을 'stubhello'로 한다.
            helloStub = sinon.stub(helloService, 'hello').returns('stubhello');
            robot = new Robot(helloService);
        });

        after(function () {
            sinon.restore();
        })

        it('test', function () {
            const name = 'yogae';
            const res = robot.start(name);
            chai.expect(res).to.be.equal('stubhello');
            chai.expect(helloStub.calledOnce).to.be.equal(true);

            const [argName] = helloStub.getCall(0).args;
            chai.expect(argName).to.be.equal(name);
        });
    });

 

stub는 hello service의 hello method를 대체하여 동작한다. spy는 hello method를 실행하지만 stub의 경우에는 실행하지 않고 stub할 때 설정한 return값을 반환하게 된다. stub는 method를 실행하지 않기 때문에 빠르게 실행되고 반환값을 지정해주어 robot 내부에서 hello method를 문제 없이 실행할 수 있게 된다. stub를 사용하면 method의 interface에만 종족성을 가지게 되고 method의 내부 로직과는 상관없이 동작하게 된다.

Mock

실제 호출이 이루어지지않고 대체된 객체를 호출하는 방식으로 test하게 된다. test code를 실행할 때마다 함수가 실행되는 것을 막고 함수의 실행을 확인하는 방식이다.

 

    describe('mock test', function () {
        let helloMock: sinon.SinonMock;
        let helloExpection: sinon.SinonExpectation;
        before(function () {
            helloMock = sinon.mock(helloService);
            helloExpection = helloMock.expects('hello');
            robot = new Robot(helloService);
        });

        after(function () {
            sinon.restore();
        })

        it('test', function () {
            const name = 'yogae';
            const res = robot.start(name);

            const [argName] = helloExpection.getCall(0).args;
            chai.expect(argName).to.be.equal(name);
            helloMock.verify();
        });
    });

 

helloService 객체는 mocking하여 사용한다. hello method가 robot 객체 안에서 호출된다. 호출되지 않는 method를 expects에 넣으면 verify할 때 error가 발생한다. mock은 hello method를 실행하지 않고 return값을 지정하지 않는다.

 

위의 code는 아래의 링크에서 볼수 있다.

https://github.com/yogae/inversify-example/blob/master/getting_started/robot.spec.ts

'develop' 카테고리의 다른 글

Error 객체 JSON.stringify()  (0) 2020.03.20
GraphQL server 구축에 유용한 module 정리  (0) 2020.03.12
2. inversify factory  (0) 2020.02.19
1. inversify 시작하기  (0) 2020.02.04
새 리전으로 AWS 리소스 마이그레이션  (0) 2020.01.29
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함