1. 개요

테스트를 작성할 때 정적 메서드를 조롱해야 하는 상황에 자주 직면하게 됩니다. Mockito 버전 3.4.0 이전에는 정적 메서드를 직접 모방할 수 없었습니다 . PowerMockito 의 도움을 통해서만 가능했습니다 .

이 사용방법(예제)에서는 최신 버전의 Mockito를 사용하여 정적 메서드를 조롱하는 방법을 살펴보겠습니다.

Mockito를 사용한 테스트에 대해 자세히 알아보려면 포괄적인  Mockito 시리즈 를 확인하십시오 .

2. 간단한 정적 유틸리티 클래스

테스트의 초점은 간단한 정적 유틸리티 클래스입니다.

public class StaticUtils {

    private StaticUtils() {}

    public static List<Integer> range(int start, int end) {
        return IntStream.range(start, end)
          .boxed()
          .collect(Collectors.toList());
    }

    public static String name() {
        return "Baeldung";
    }
}

데모 목적으로 몇 가지 인수가 있는 메서드 하나와 단순히 String 을 반환하는 다른 메서드가 있습니다 .

3. 정적 메서드를 위한 Mockito 구성

정적 메서드를 Mocking 위해 Mockito를 사용하기 전에 인라인 MockMaker 를 활성화하도록 구성해야 합니다 .

프로젝트의  src/test/resources/mockito-extensions  디렉토리  에 org.mockito.plugins.MockMaker 라는 텍스트 파일을  추가하고 한 줄의 텍스트를 추가해야 합니다.

mock-maker-inline

4. 정적 메서드 테스트에 대한 간략한 설명

일반적으로 일부 사람들은 깨끗한 객체 지향 코드를 작성할 때 정적 클래스를 모의할 필요가 없다고 말할 수 있습니다. 이는 일반적으로 응용 프로그램의 디자인 문제 또는 코드 냄새 를 암시할 수 있습니다.

왜요? 첫째, 정적 메서드에 의존하는 클래스는 밀접하게 결합되어 있고 둘째, 거의 항상 테스트하기 어려운 코드로 이어집니다. 이상적으로는 클래스가 의존성을 가져오는 데 책임이 없어야 하며 가능하면 외부에서 주입되어야 합니다.

따라서 테스트 가능성을 높이기 위해 코드를 리팩터링할 수 있는지 항상 조사할 가치가 있습니다. 물론 이것이 항상 가능한 것은 아니며 때로는 정적 메서드를 조롱해야 합니다.

5. 인수가 없는 정적 메서드 Mocking

계속해서 StaticUtils 클래스 에서 name 메서드를 조롱하는 방법을 살펴보겠습니다 .

@Test
void givenStaticMethodWithNoArgs_whenMocked_thenReturnsMockSuccessfully() {
    assertThat(StaticUtils.name()).isEqualTo("Baeldung");

    try (MockedStatic<StaticUtils> utilities = Mockito.mockStatic(StaticUtils.class)) {
        utilities.when(StaticUtils::name).thenReturn("Eugen");
        assertThat(StaticUtils.name()).isEqualTo("Eugen");
    }

    assertThat(StaticUtils.name()).isEqualTo("Baeldung");
}

이전에 언급했듯이 Mockito 3.4.0부터 Mockito.mockStatic( Class<T> classToMock ) 메서드를 사용하여 정적 메서드 호출에 대한 모의 호출을 할 수 있습니다. 이 메서드는 범위가 지정된 모의 개체인 유형에 대한 MockedStatic 개체를 반환합니다.

따라서 위의 단위 테스트에서 유틸리티 변수는 스레드 로컬 명시적 범위가 있는 모의 객체를 나타냅니다. 범위가 지정된 모의 개체는 모의 개체를 활성화하는 엔터티에 의해 닫혀야 한다는 점에 유의하는 것이 중요합니다. 이것이 우리 가 범위가 지정된 블록을 완료할 때 모의가 자동으로 닫히도록 try-with-resources 구성 내에서 모의를 정의하는 이유입니다.

이는 정적 모의 객체가 일시적으로 유지되도록 보장하기 때문에 특히 좋은 기능입니다. 아시다시피 테스트 실행 중에 정적 메서드 호출을 가지고 놀면 테스트 실행의 동시 및 순차적 특성으로 인해 테스트 결과에 부정적인 영향을 미칠 수 있습니다.

게다가 또 다른 좋은 부작용은 Mockito가 모든 테스트에 대해 클래스 로더를 교체할 필요가 없기 때문에 테스트가 여전히 매우 빠르게 실행된다는 것입니다.

이 예제에서는 범위가 지정된 블록 전후에 정적 메서드 이름 이 실제 값을 반환하는지 확인하여 이 점을 반복합니다.

6. 인수로 정적 메서드 Mocking

이제 인수가 있는 메서드를 조롱해야 하는 또 다른 일반적인 사용 사례를 살펴보겠습니다.

@Test
void givenStaticMethodWithArgs_whenMocked_thenReturnsMockSuccessfully() {
    assertThat(StaticUtils.range(2, 6)).containsExactly(2, 3, 4, 5);

    try (MockedStatic<StaticUtils> utilities = Mockito.mockStatic(StaticUtils.class)) {
        utilities.when(() -> StaticUtils.range(2, 6))
          .thenReturn(Arrays.asList(10, 11, 12));

        assertThat(StaticUtils.range(2, 6)).containsExactly(10, 11, 12);
    }

    assertThat(StaticUtils.range(2, 6)).containsExactly(2, 3, 4, 5);
}

여기서는 동일한 접근 방식을 따르지만 이번에는 우리가 모의하려는 인수와 함께 메서드를 지정하는 when 절 안에 람다 식 을 사용합니다. 꽤 직설적 인!

7. 결론

이 빠른 기사에서 우리는 Mockito를 사용하여 정적 메소드를 조롱하는 방법에 대한 몇 가지 예를 보았습니다. 요약하면 Mockito는 하나의 작은 람다를 통해 조롱된 정적 객체에 대해 더 좁은 범위를 사용하는 우아한 솔루션을 제공합니다.

언제나처럼 기사의 전체 소스 코드는  GitHub에서 확인할 수 있습니다 .

Junit footer banner