테스트 컨테이너의 적용 범위

에러 원인

@TestConfiguration  
public class TestContainerConfig implements BeforeAllCallback {  
  
    public static final String REDIS_IMAGE = "redis:7.4.0-alpine";  
    public static final String KAFKA_IMAGE = "confluentinc/cp-kafka:7.7.1.arm64";
    ...
}

위와 같이 테스트 컨테이너를 작성한 후에 아래와 같이
Spring에서 기본으로 제공하는 테스트를 동작하려고 하였다.
나는 당연히 여기서도 ComponentScan으로 아래에 있는 Configuration을 탐색할 줄 알았으나
탐색을 하지 않았다.

@SpringBootTest  
class AuthApplicationTests {  
  
    @Test  
    void contextLoads() {  
    }  
  
}

해결 방법

@ExtendWith(TestContainerConfig.class)  
@SpringBootTest  
class OrderApplicationTests {  
  
    @Test  
    void contextLoads() {  
    }  
  
}

ExtendWith 어노테이션을 사용해서 사용할 Configuration들을 주입해줘야 한다.

Wrapper type을 mocking 하려 하는 경우

에러 코드

String key = mock(String.class);  
String value = mock(String.class);  
Long duration = mock(Long.class);
 
doNothing().when(redisUtil)
	.setDataExpire(key, value, duration);

위와 같이 테스트 중에 만들어질 호출에 대해서 고정값이 아닌 타입이 들어올 것이라고 생각해서
타입으로 Stub을 하려고 하였다.
그랬더니 아래와 같은 에러가 발생하였다.

org.mockito.exceptions.base.MockitoException: 
Cannot mock/spy class java.lang.Long
Mockito cannot mock/spy because :
 - Cannot mock wrapper types, String.class or Class.class

해결 방법

mockito의 ArgumentMatchers를 사용해서 타입을 넣어줄 수 있다.

import static org.mockito.ArgumentMatchers.anyString;  
import static org.mockito.ArgumentMatchers.eq;
 
doNothing().when(redisUtil)
	.setDataExpire(anyString(), anyString(), eq(60 * 5L));

어떤 String이건 들어올 수 있다고 판단되는 경우 anyString()과 같은 메서드를 사용하면 되고
정확한 값을 지정하고 싶으면 eq()를 사용하면 된다.

통합테스트에서 verify()를 사용하려한 경우

발생한 문제

테스트 과정중에 mongoTemplate이 호출되었나 확인하기 위해서 아래와 같이 작성을 하였다.

@Autowired  
private MongoTemplate mongoTemplate;
 
verify(mongoTemplate, times(1)).query(any());
 

하지만 이렇게 의존성을 주입한 객체를 verify를 호출해서 실행을 했더니 아래와 같은 에러가 발생하였다.

org.mockito.exceptions.misusing.NotAMockException: 
Argument passed to verify() is of type {verify를 원하는 클래스} and is not a mock!

해결 방법

  • 위의 테스트를 단위 테스트로 변경한다.
  • SpyBean을 사용한다.

SpyBean을 사용해서 감싸주는 예시

아래와 같이 주입을 원하는 클래스를 SpyBean으로 선언해준다.

@SpyBean  
private MongoTemplate mongoTemplate;

위와 같이 SpyBean을 사용해서 원하는 클래스를 Mockito로 감싸주면 아래와 같이 verify 사용이 가능하다.

verify(mongoTemplate, times(0)).query(Cart.class);