BACKEND/Spring Boot

테스트 스텁과 목 오브젝트의 차이점

chaerrii 2024. 9. 19. 00:03

두 가지를 포함한 범위인 테스트 대역을 먼저 정리한다.

테스트 대역(Test Double) 이란?



테스트를 하려는 객체가 다른 객체들과 여러 관계가 엮여있어 사용하기 어려울 때, 대체할 수 있는 객체를 말한다.

테스트 대역은 Dummy, Stub, Spy, Mock, Fake로 나눌 수 있다.

Dummy 

객체는 전달되지만 실제로 사용되지는 않는다. 일반적으로 매개변수 목록을 채운다.

Fake

실제로 작동하나 일반적으로 프로덕션에는 적합하지 않는 방식을 취한다.

Stub

테스트 중 만들어진 호출에 미리 준비된 답변을 제공하고 일반적으로 테스트를 위해 프로그래밍된 것 외에는 전혀 응답하지 않는다.

Spy

그들이 어떻게 호출되었는지에 따라 일부 정보를 기록하는 스텁이다.

Mock

호출될 것으로 예상되는 사양을 형성하는 기댓값으로 미리 프로그래밍된 객체다.

 

...

그 중 Stub과 Mock 에 대해 자세히 알아보자.

Stub

인스턴스화하여 구현한 가짜 = Dummy 객체이다. 실제로 동작하는 것처럼 보이게 만드는 객체이다.

해당 인터페이스와 클래스를 최소한으로 구현한다. 

테스트에서 호출된 요청에 대해 미리 준비해둔 결과를 전달한다.

Mock

호출에 대한 기대를 명세하고, 내용에 따라 동작하도록 프로그래밍 된 객체이다. 

테스트 작성을 위한 환경 구축이 어려울 때, 테스트 하고자 하는 코드와 엮인 객체들을 대신하기 위해 만들어진 객체이다. 

 

쉽게 둘을 헷갈리곤 하지만, 목 오브젝트는 행위 검증(behavior verification) 을 사용하고,
스텁을 포함한 다른 대역들은 상태 검증(state verification)을 사용한다.

행위 검증이란?

메소드의 리턴 값으로 판단할 수 없는 경우 특정 동작을 수행하는 지를 확인한다.

값을 구체적으로 비교하지 않으나 목 오브젝트의 지원을 받아 별도의 코드 없이 메소드 호출 여부 등을 간단하게 검사할 수 있음.

 public void testOrderSendsMailIfUnfilled() {
    Order order = new Order(TALISKER, 51);
    Mock warehouse = mock(Warehouse.class);
    Mock mailer = mock(MailService.class);
    order.setMailer((MailService) mailer.proxy());

    mailer.expects(once()).method("send");
    warehouse.expects(once()).method("hasInventory")
      .withAnyArguments()
      .will(returnValue(false));

    order.fill((Warehouse) warehouse.proxy());
  }

상태 검증이란?

메소드가 수행된 후, 객체의 상태를 확인해 올바르게 동작했는지를 확인한다.

  public void testOrderSendsMailIfUnfilled() {		// 상태 검증
    Order order = new Order(TALISKER, 51);
    MailServiceStub mailer = new MailServiceStub();
    order.setMailer(mailer);
    order.fill(warehouse);
    assertEquals(1, mailer.numberSent());		// 올바른 상태 값이 나오는지 체크(테스트)
  }

 

처음엔 Mock을 정의하기 위해 데이터와 기대치 부분을 나눈다.

//data
Order order = new Order();
Mock warehouseMock = new Mock(Warehouse.class);

//기대치 설정
warehouseMock.expects(once().method("hasInventory")
			  .with...)
              .will(returnValue(true));
//exercise
order.fill((Warehouse) warehouseMock.proxy());
//검증
warehouseMock.verify();
assertTrue(order.isFilled());

출처: https://github.com/team-tancheon/book-lounge/issues/16 ,https://jaime-note.tistory.com/330