tools & libs/단위테스트(junit, spock)

[junit] static method mocking

  • -

이번 포스트에서는 mockito-inline을 이용해서 LocalDateTime.now() 같은 static method를 mocking 해보자.

 

mockito-inline을 이용한 static method mocking

 

mockito-inline

정확하지는 않지만 몇 년 전에 시간 기반의 테스트를 해야했는데 아주 고생한 기억이 있다. 기본적으로 시간을 테스트하려면 LocalDateTime.now() 같은 메서드를 mock 해야 하는데 mockito는 static 메서드를 지원하지 않았다.

그러다 간만에 찾아보니 mockito-inline이라는 라이브러리에서 static method에 대한 mocking이 지원되는 것을 발견했다. 유레카!! 

<!-- https://mvnrepository.com/artifact/org.mockito/mockito-inline -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>5.2.0</version>
    <scope>test</scope>
</dependency>

 

시간의 고정

LocalDateTime.now()를 mocking하는 이유는 특정 시간으로 고정하고 싶어서이다. 시간을 고정하기 위해서는 Clock이라는 클래스의 static method인 fixed를 사용하면 된다.

String instantExpected = "2000-01-01T00:00:00Z";
Clock clock = Clock.fixed(Instant.parse(instantExpected), ZoneId.of("UTC"));
LocalDateTime fake = LocalDateTime.now(clock);

위의 코드를 이용하면 2000-01-01:0:0:0 초로 고정된 fake를 얻게 되었는데 mock을 이용해서 현재 시간을 fake로 고정해보자.

 

mockStatic

static method를 mocking 하기 위해서는 mockStatic 메서드를 사용한다. 대부분의 static method들을 시스템 전반에 영향을 끼치게 되므로 테스트 후 추가적인 side effect를 없애기 위해 원래대로 돌려놓는 작업이 필요하다. mockStatic에서는 이를 위해 return type으로 MockedStatic<T> 객체를 반환 하는데 이녀석이 AutoCloseable이다. 따라서 try~with~resource 문장에서 MockedStatic을 사용하고 테스트가 끝나면 자동 종료시켜주는 패턴을 이용한다.

@Test
public void givenInstantMock_whenNow_thenGetFixedInstant() {
    String instantExpected = "2000-01-01T00:00:00Z";
    Clock clock = Clock.fixed(Instant.parse(instantExpected), ZoneId.of("UTC"));
    LocalDateTime fake = LocalDateTime.now(clock);
    
    try (MockedStatic<LocalDateTime> mockedStatic = mockStatic(LocalDateTime.class)) {
        mockedStatic.when(LocalDateTime::now).thenReturn(fake);
        LocalDateTime returned = method();
        assertEquals(returned.getYear(), fake.getYear());
        assertEquals(returned.getMonth(), fake.getMonth());
    }
}

public LocalDateTime method() {
    // system의 시간을 얻어온다.
    LocalDateTime now = LocalDateTime.now();
    return now;
}

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.