Backend/Spring Boot

[Spring/JUnit] Mock ๊ฐ์ฒด ์„ค์ • ๋ฌธ์ œ : java.lang.AssertionError: Expecting actual not to be null

giraffe_ 2024. 8. 19. 16:23

โ—๏ธ์—๋Ÿฌ ๋ฉ”์‹œ์ง€


java.lang.AssertionError: Expecting actual not to be null

 

 

 

 

 

๐Ÿ’ป ๊ฐœ๋ฐœ ํ™˜๊ฒฝ


  • Framework : Spring Boot `3.2.3`
  • DB : MySQL(๋กœ์ปฌ), H2(ํ…Œ์ŠคํŠธ)
  • Library : JPA, QueryDSL `5.0.0`
  • Test : JUnit

 

 

 

 

 

๐Ÿ”Ž ์›์ธ


Spring์—์„œ Junit์œผ๋กœ Service ๋‹จ์˜ ๊ฒŒ์‹œ๊ธ€ ๋“ฑ๋ก ๊ธฐ๋Šฅ์„ ํ…Œ์ŠคํŠธํ•˜๋Š”๋ฐ ์—๋Ÿฌ๊ฐ€ ๋‚ฌ๋‹ค.

๊ฒŒ์‹œ๊ธ€ ๋“ฑ๋ก ๋ฉ”์†Œ๋“œ๋Š” `save()`๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ , ์ƒˆ๋กœ ๋“ฑ๋ก๋œ ๊ฒŒ์‹œ๊ธ€์˜ `id`๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

์ด๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด Mock ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด `save()`๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉด ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ–ˆ๊ณ , `getId()`๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด `id`๋กœ 1L์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์„ค์ •ํ–ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ฒŒ์‹œ๊ธ€ ๋“ฑ๋ก ๋ฉ”์†Œ๋“œ๋ฅผ ์‹คํ–‰ํ–ˆ์„ ๋•Œ ๋ฐ˜ํ™˜๊ฐ’์ด ์„ค์ •ํ•œ `id` ๊ฐ’๊ณผ ๊ฐ™์€์ง€๋ฅผ ๊ฒ€์ฆํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

 

 

 

    @Test
    @DisplayName("๊ตฌ์ง ๊ฒŒ์‹œ๊ธ€ ์ƒ์„ฑ")
    public void createHiringPostTest() {
        // given
        HiringPostReq hiringPostReq = HiringPostReq.builder()
                ...
                .build();

        ...

        HiringPost mockHiringPost = mock(HiringPost.class);
        when(hiringPostRepository.save(any(HiringPost.class))).thenReturn(mockHiringPost);
        when(mockHiringPost.getId()).thenReturn(1L);

        // when
        Long resultId = hiringPostServiceImpl.registerHiringPost(hiringPostReq);
        
        //๊ฐ์ฒด ํ™•์ธ์„ ์œ„ํ•œ print
        HiringPost savedHiringPost = hiringPostRepository.save(any(HiringPost.class));
        System.out.println("hiringPost: " + savedHiringPost);
        System.out.println("resultId: " + resultId);

        // then
        assertThat(resultId).isNotNull();
        assertThat(resultId).isEqualTo(1L);

        ...
        verify(hiringPostRepository, times(1)).save(any(HiringPost.class));
    }

 

 

 

 

์ œ๋Œ€๋กœ `save()`์™€ `getId()` ๋ฉ”์†Œ๋“œ๊ฐ€ ์‹คํ–‰๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด์„œ ํ”„๋ฆฐํŠธ๋ฅผ ์ฐ์–ด๋ดค๋‹ค.

`save()`๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด ๊ฒฐ๊ณผ๊ฐ’์œผ๋กœ `null`์ด ๋‚˜์™”๊ณ , `getId()`๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์„œ๋น„์Šค ๋ฉ”์†Œ๋“œ ๊ฒฐ๊ณผ๊ฐ’์ธ `resultId`๊ฐ€ null์ด ๋‚˜์™”๋‹ค.

 

์„œ๋น„์Šค์—์„œ `save()`๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ, Mockito๊ฐ€ Mock ๊ฐ์ฒด(mockHiringPost)๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด๋‹ค. ์„œ๋น„์Šค ๋ฉ”์†Œ๋“œ์˜ ๋‚ด๋ถ€์—์„œ ์ƒˆ๋กœ ์ƒ์„ฑ๋œ ๊ฐ์ฒด(HiringPost)๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

Mock ๊ฐ์ฒด์™€ ์‹ค์ œ ๊ฐ์ฒด๊ฐ€ ํ˜ผ์šฉ์ด ๋˜๊ณ  ์žˆ์—ˆ๋‹ค.. (์ง€๊ธˆ ํฌ์ŠคํŒ…์„ ์“ฐ๋Š” ์ˆœ๊ฐ„์—๋„ ํ—ท๊ฐˆ๋ฆฐ๋‹ค๐Ÿ˜…)

 

 

 

 

 

๐Ÿ’ก ํ•ด๊ฒฐ


`save()`๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ, Mock ๊ฐ์ฒด๊ฐ€ ์•„๋‹ˆ๋ผ ์‹ค์ œ ๊ฐ์ฒด๊ฐ€ ์‚ฌ์šฉ๋˜๋„๋ก ํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์‹ค์ œ ๊ฐ์ฒด์˜ id ๊ฐ’์„ ์„ค์ •ํ•ด์ค€๋‹ค.

 

 

when(hiringPostRepository.save(any(HiringPost.class))).thenAnswer(invocation -> {
	HiringPost hiringPost = invocation.getArgument(0);
	ReflectionTestUtils.setField(hiringPost, "id", 1L);
	return hiringPost;
});

 

  • ๋™์ž‘์„ ๋” ์ƒ์„ธํžˆ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•ด์„œ `thenAnswer`์„ ์‚ฌ์šฉํ•œ๋‹ค. `invocation`์€ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ, ๋ฐ˜ํ™˜๊ฐ’์„ ๊ฐ€์ ธ์™€ ๋™์ž‘์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค.
  • `invocation.getArgument(0)`์˜ ๊ฒฐ๊ณผ๋กœ ์ €์žฅํ•˜๋ ค๋Š” HiringPost ๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋œ๋‹ค.
  • ์ž๋™์œผ๋กœ id๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ง์ ‘ id๋ฅผ ์„ค์ •ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

 

id ์„ค์ • ๋ถ€๋ถ„์—์„œ `ReflectionTestUtils`์„ ์‚ฌ์šฉํ•ด์•ผ ํ–ˆ๋‹ค.

๊ฐ์ฒด์˜ ํ•„๋“œ๊ฐ€ private์œผ๋กœ ์ •์˜๋˜์–ด ์žˆ๊ธฐ๋„ ํ•˜๊ณ , ์™ธ๋ถ€์—์„œ ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋„๋ก setter ์‚ฌ์šฉ์„ ๋ง‰์•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

 

 

 

 

๐Ÿ“– ์ฐธ๊ณ