스프링 부트 테스트(1) - 속도 비교

hyungjunn·2024년 6월 2일
0
post-thumbnail

인터넷의 많은 예제들을 살펴보면, 각각 테스트를 다 다르게 작성하는 것을 볼 수 있다. 이 글에서 어느 계층에서 어떤 테스트를 선택하고 작성해야 효율적인건지 알아본다.

테스트 환경

  • M1 Mac
  • Java 17
  • SpringBoot 3.2.2
  • gradle 8.5
  • H2 2.2.224

Service layer 에서의 테스트

@SpringBootTest

@SpringBootTest  
class TeamServiceTest {  
  
    @Autowired  
    private TeamService teamService;  
  
    @Test  
    @Transactional(propagation = Propagation.NOT_SUPPORTED)  
    void test() {  
        Long teamId = teamService.registerTeam("Ateam");  
  
        Assertions.assertThat(teamId).isEqualTo(1L);  
    }  
}
실행 시간
첫번째1sec 279ms
두번째955ms
세번째851ms
네번째1sec 8ms
다섯번째984ms
평균1015.4ms

@ExtendWith(MockitoExtension.class)

@SpringBootTest와 똑같은 방식으로 측정한다.

@ExtendWith(MockitoExtension.class)  
class TeamService2Test {  
  
    @InjectMocks  
    private TeamService teamService;  
  
    @Mock  
    private TeamRepository teamRepository;  
  
    @Test  
    void test() {  
        Team team = new Team(1L,"Ateam", "hyungjunn", 0);  
  
        BDDMockito.given(teamRepository.save(any(Team.class)))  
                .willReturn(team);  
  
        Long teamId = teamService.registerTeam("Ateam");  
  
        Assertions.assertThat(teamId).isEqualTo(1L);  
    }  
}

각각 측정한 결과를 표로 나타내면 다음과 같다.

@SpringBootTest@ExtendWith
첫번째1sec 279ms1sec 797ms
두번째955ms2sec 130ms
세번째851ms1sec 760ms
네번째1sec 8ms1sec 795ms
다섯번째984ms1sec 803ms
평균1015.4ms1857.0ms

나의 가설은 당연히 서버를 실행시켜야 되는@SpringBootTest@ExtendWith(MockitoExtension.class) 보다 느리다는 것이었다.

하지만, 위의 측정 결과는 잘못되었다.

성능 측정을 할때에는 JVM워밍업, I/O 작업 등 외부요인의 영향을 최대한 받지 않아야 하는데, ms단위의 작업은 외부요인이 더 영향을 주는 단계이기 때문이다.

그렇다면 여러번 테스트를 실행시켰을 때는 어떨까? 코드를 재구성해서 측정을 해본다.

@SpringBootTest  
class TeamServiceTest {  
  
    @Autowired  
    private TeamService teamService;  
  
    private static final int REPEAT_COUNT = 1_000; // 반복 횟수 설정  
    private static long totalExecutionTime = 0;  
  
    @Order(1)  
    @RepeatedTest(REPEAT_COUNT)  
    @Transactional(propagation = Propagation.NOT_SUPPORTED)  
    void test() {  
        long startTime = System.nanoTime();  
        Long teamId = teamService.registerTeam("Ateam");  
        long endTime = System.nanoTime();  
        long executionTime = endTime - startTime;  
        totalExecutionTime += executionTime;  
  
        Assertions.assertThat(teamId).isNotNull().isGreaterThan(0);  
    }
  
    @Order(2)  
    @Test  
    void calculateAverageExecutionTime() {  
        long averageExecutionTime = totalExecutionTime / REPEAT_COUNT;  
        System.out.println("SpringBootTest - Average execution time (ns): "
            + averageExecutionTime);  
    }  
}
@ExtendWith(MockitoExtension.class)  
class TeamService2Test {  
  
    @InjectMocks  
    private TeamService teamService;  
  
    @Mock  
    private TeamRepository teamRepository;  
  
    private static final int REPEAT_COUNT = 1_000; // 반복 횟수 설정  
    private static long totalExecutionTime = 0;  
  
    @Order(1)  
    @RepeatedTest(REPEAT_COUNT)  
    void test() {  
        Team team = new Team(1L, "Ateam", "hyungjunn", 0);  
        BDDMockito.given(teamRepository.save(any(Team.class)))
            .willReturn(team);  
  
        long startTime = System.nanoTime();  
        Long teamId = teamService.registerTeam("Ateam");  
        long endTime = System.nanoTime();  
        long executionTime = endTime - startTime;  
        totalExecutionTime += executionTime;  
  
        Assertions.assertThat(teamId).isNotNull().isGreaterThan(0);  
    }  
  
    @Order(2)  
    @Test  
    void calculateAverageExecutionTime() {  
        long averageExecutionTime = totalExecutionTime / REPEAT_COUNT;  
        System.out.println("MockitoExtension - Average execution time (ns): "
            + averageExecutionTime);  
    }  
}

여러 번 테스트를 실행시켰을 때의 결과는 아래와 같다.

반복 횟수@SpringBootTest@ExtendWith
50번1sec 549ms2sec 43ms
1000번6sec 543ms3sec 796ms
5000번16sec 385ms6sec 287ms

50번일 때는 별로 차이가 안나는 거 같으나, 더 많은 데이터가 실행되면 될 수록 차이가 훨씬 많이 벌어지는 것을 관찰할 수 있었다.

0개의 댓글