Mockito๋ฅผ ์ด์šฉํ•œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ

2023. 12. 10. 16:35ยท ๐’๐ฉ๐ซ๐ข๐ง๐ 
๋ชฉ์ฐจ
  1. 1. Mockito๋ž€?
  2. 2. ์ปจํŠธ๋กค๋Ÿฌ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ 
  3. (1) @WebMvcTest๋ฅผ ํ†ตํ•ด ์›น ๊ณ„์ธต ํ…Œ์ŠคํŠธ ์ค€๋น„
  4. (2) ํ•„์š”ํ•œ ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐ ์ฃผ์ž…ํ•˜๊ธฐ
  5. (3) ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ ์ž‘์„ฑ
  6. (4) ์‹คํ–‰ ๊ฒฐ๊ณผ ํ™•์ธ
  7. 3. ์„œ๋น„์Šค ๋‹จ์œ„ ํ…Œ์ŠคํŠธ
  8. (1) Junit๊ณผ Mockito ๊ฒฐํ•ฉํ•˜๊ธฐ
  9. (2) ๊ฐ€์งœ ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐ ์ฃผ์ž…ํ•˜๊ธฐ
  10. (3) ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ ์ž‘์„ฑ
  11. (4) ์‹คํ–‰ ๊ฒฐ๊ณผ ํ™•์ธ
  12. 4. ์ฐธ๊ณ ์ž๋ฃŒ

 ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ ์ฒ˜์Œ์œผ๋กœ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณด์•˜๋‹ค.
๊ทธ ์ „์—๋Š” ์ธ๊ฐ• ๊ฐ•์‚ฌ๋‹˜์ด ์น˜๋Š” ๊ฒƒ๋งŒ ๋”ฐ๋ผ์ณ๋ดค๋Š”๋ฐ, ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•˜๋ ค๋‹ˆ ์Šคํ”„๋ง๋ถ€ํŠธ๊ฐ€ ๋œจ๋Š” ๋ฐ ๋„ˆ๋ฌด ์˜ค๋ž˜ ๊ฑธ๋ ธ๋‹ค๐Ÿฅฒ
์ •ํ™•ํ•œ ์‹œ๊ฐ„์€ ์žฌ๋ณด์ง€ ์•Š์•˜์ง€๋งŒ ๋Œ€๋žต 3~5์ดˆ์˜ ์‹œ๊ฐ„์ด ๊ฑธ๋ ธ๊ณ , ์ด์— ๋Œ€ํ•œ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์„ ์ฐพ๋‹ค๊ฐ€ Mockito๋ผ๋Š” ๊ฑธ ์‚ฌ์šฉํ•ด๋ณด๊ฒŒ ๋˜์—ˆ๋‹ค.
 

1. Mockito๋ž€?

Mockito๋Š” Mock, ์‰ฝ๊ฒŒ ๋งํ•ด ๊ฐ€์งœ ๊ฐ์ฒด๋ฅผ ์ง€์›ํ•ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค. ๊ฐ€์งœ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ํŽธํ•ด์ง„๋‹ค.
 
๊ธฐ์กด์˜ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋Š” ๋ชจ๋“  ๋นˆ์„ ๋„์šฐ๊ธฐ ๋•Œ๋ฌธ์— ์‹คํ–‰ํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฐ๋‹ค. ๋˜ํ•œ ๋‹ค๋ฅธ ํด๋ž˜์Šค์˜ ์ •์ƒ ๋™์ž‘ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐ”๋€๋‹ค๋Š” ๋ฌธ์ œ์ ์ด ์žˆ์—ˆ๋‹ค.  Service์˜ createTag()๊ฐ€ ์ •์ƒ ๋™์ž‘ํ•˜๋Š” ๊ฑธ ํ™•์ธํ•˜๊ณ  ์‹ถ์–ด๋„, Repository์— ๋ฌธ์ œ๊ฐ€ ์žˆ์œผ๋ฉด createTagTest() ๋ฉ”์„œ๋“œ ์ž์ฒด๊ฐ€ ์‹คํŒจํ•˜๋Š” ์‹์ด๋‹ค.
 
๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ๊ฐ€์งœ ๊ฐ์ฒด ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ์ง€๋งŒ, ํ…Œ์ŠคํŠธ์šฉ ๊ฐ€์งœ ๊ฐ์ฒด ํด๋ž˜์Šค๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ฑด ๋ฒˆ๊ฑฐ๋กญ๊ณ  ๊ท€์ฐฎ๋‹ค.
์•„๋งˆ ๊ท€์ฐฎ์Œ์„ ์ด๊ธฐ์ง€ ๋ชปํ•œ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ด๋ ‡๊ฒŒ ์ข‹์€๊ฑธ ๋งŒ๋“ค์–ด์ค€๊ฒŒ ์•„๋‹๊นŒ~?๐Ÿคทโ€โ™€๏ธ 
 
์ด๋Ÿฌํ•œ ์ด์œ ๋กœ Mockito๋ฅผ ์ด์šฉํ•ด ๊ฐ€์งœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์—ฌ, ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์— ๋„์ „ํ•ด๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค๐Ÿ”ฅ

 

2. ์ปจํŠธ๋กค๋Ÿฌ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ 

@RestController
@RequestMapping("/api/v1/tags")
@RequiredArgsConstructor
public class TagController {

    private final Long TEMP_USER_ID = 1L;

    private final TagService tagService;

    @PostMapping
    public ResponseEntity<Void> createTag(@RequestBody @Valid final TagCreateRequest request) {
        tagService.save(TEMP_USER_ID, request);

        return ResponseEntity.noContent().build();
    }
}

 

"/api/v1/tags"๋ผ๋Š” Path๋กœ POST ์š”์ฒญ์„ ๋ณด๋‚ด, ์‘๋‹ต์ฝ”๋“œ 204๊ฐ€ ์ œ๋Œ€๋กœ ์˜ค๋Š”์ง€๋ฅผ ํ…Œ์ŠคํŠธํ•ด๋ณด์ž.

 

(1) @WebMvcTest๋ฅผ ํ†ตํ•ด ์›น ๊ณ„์ธต ํ…Œ์ŠคํŠธ ์ค€๋น„

@WebMvcTest(TagController.class)
class TagControllerTest {
	...
}

 

- @WebMvcTest: SpringMVC ์ปดํฌ๋„ŒํŠธ์—๋งŒ ์ง‘์ค‘ํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด ์ฃผ๋Š” ์• ๋…ธํ…Œ์ด์…˜์ด๋‹ค.

 

@WebMvcTest๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ „์ฒด ์ปจํ…์ŠคํŠธ๊ฐ€ ์•„๋‹Œ TagController์™€ ๊ด€๋ จ๋œ ์›น ๊ณ„์ธต ๋นˆ๋“ค๋งŒ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋‹ค. (๋”ฐ๋ผ์„œ Controller, Filter, JsonComponent ๋“ฑ์€ ๋กœ๋“œ๋˜์ง€๋งŒ, Service, Repository ๋“ฑ์€ ๋กœ๋“œ๋˜์ง€ ์•Š๋Š”๋‹ค.)

์ฐธ๊ณ ๋กœ @WebMvcTest๊ฐ€ ๋ถ™์€ ํ…Œ์ŠคํŠธ๋Š” MockMvc์™€ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ๊ฐ€ ์ž๋™์œผ๋กœ ์„ค์ •๋˜์–ด ์žˆ๋‹ค.

 

(2) ํ•„์š”ํ•œ ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐ ์ฃผ์ž…ํ•˜๊ธฐ

@WebMvcTest(TagController.class)
class TagControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @MockBean
    private TagService tagService;
}

 

- MockMvc: ์„œ๋ฒ„ ์‚ฌ์ด๋“œ Spring MVC ํ…Œ์ŠคํŠธ๋ฅผ ์ง€์›ํ•˜๋Š” ํด๋ž˜์Šค๋กœ, HTTP ์š”์ฒญ ๋ฐ ์‘๋‹ต์˜ ์‹œ๋ฎฌ๋ ˆ์ด์…˜์„ ๋‹ด๋‹นํ•œ๋‹ค.

- ObjectMapper: ๊ฐ์ฒด โ‡” JSON ์‚ฌ์ด์˜ ๋ณ€ํ™˜์„ ๋‹ด๋‹นํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” RequestDTO๋ฅผ JSON์œผ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ HTTP Request Body์— ๋„ฃ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜์˜€๋‹ค.

- @MockBean: ๊ฐ€์งœ ๋นˆ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์ค€๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” @WebMvcTest์— ์˜ํ•ด ์Šคํ”„๋ง ์ปจํ…์ŠคํŠธ์˜ ์ผ๋ถ€๊ฐ€ ๋กœ๋“œ๋˜์—ˆ์œผ๋ฏ€๋กœ, @Mock ๋Œ€์‹   @MockBean์„ ์‚ฌ์šฉํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

 

(3) ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ ์ž‘์„ฑ

@Test
void ํƒœ๊ทธ_๋“ฑ๋ก_์š”์ฒญ์„_์„ฑ๊ณตํ•œ๋‹ค() throws Exception {
    // given
    final TagCreateRequest tagCreateRequest = new TagCreateRequest("tag_Name");


    // when
    final ResultActions resultActions = mockMvc.perform(post("/api/v1/tags")
                    .contentType(MediaType.APPLICATION_JSON)
                    .content(objectMapper.writeValueAsString(tagCreateRequest)));

    // then
    resultActions.andExpect(status().isNoContent());
}

 

๋จผ์ € ์š”์ฒญ์— ์ด์šฉํ•  RequestDTO๋ฅผ ์ƒ์„ฑํ•œ ๋‹ค์Œ, MockMvc.perform()์„ ์ด์šฉํ•ด HTTP Request๋ฅผ ๋ณด๋‚ธ๋‹ค.

 

perform()์€ HTTP ์š”์ฒญ์„ ์‹œ๋ฎฌ๋ ˆ์ดํŠธํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ๋ฉ”์„œ๋“œ๋กœ, ์ฒด์ด๋‹์„ ํ†ตํ•ด GET, POST ๋“ฑ์˜ HTTP Method์™€ ์š”์ฒญ ํ—ค๋”, ์ฟ ํ‚ค ๊ฐ’์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. (Content-Type ํ—ค๋”๊ฐ€ application/json์ž„์— ์ฃผ์˜ํ•˜์ž.)

ObjectMapper๋ฅผ ์ด์šฉํ•ด RequestDTO ๊ฐ์ฒด๋ฅผ JSON์œผ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ Request Body์— ๋‹ด์•„ ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด, ๊ทธ์— ๋Œ€ํ•œ ์‘๋‹ต์€ ResultAction์— ๋‹ด๊ธด๋‹ค.

 

ResultAction์€ HTTP ์‘๋‹ต์„ ๊ฒ€์ฆํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋˜๋Š” ํด๋ž˜์Šค๋กœ, ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์›ํ•œ๋‹ค.

- andExpect(): ์‘๋‹ต ์ฝ”๋“œ, ์‘๋‹ต ๋ฐ”๋””์— ๋‹ด๊ธด ๋‚ด์šฉ ๋“ฑ์„ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋‹ค. ๋งŒ์•ฝ ๊ธฐ๋Œ€๊ฐ’๊ณผ ์‹ค์ œ ๊ฒฐ๊ณผ๊ฐ’์ด ๋‹ค๋ฅผ ๊ฒฝ์šฐ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

- andDo(): ์‘๋‹ต ๋‚ด์šฉ์„ ์ถœ๋ ฅํ•˜๊ฑฐ๋‚˜ ๋กœ๊ทธ์— ๊ธฐ๋กํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

- andReturn(): ์‘๋‹ต ๊ฒฐ๊ณผ๋ฅผ MvcResult ๋ผ๋Š” ๊ฐ์ฒด์— ๋‹ด์•„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

์—ฌ๊ธฐ์„œ๋Š” ์‘๋‹ต์ฝ”๋“œ 204๋ฅผ ๋ฐ˜ํ™˜์„ ๊ธฐ๋Œ€ํ•˜๋„๋ก ์„ค์ •ํ–ˆ๋‹ค.

 

(4) ์‹คํ–‰ ๊ฒฐ๊ณผ ํ™•์ธ

 


3. ์„œ๋น„์Šค ๋‹จ์œ„ ํ…Œ์ŠคํŠธ

@Service
@RequiredArgsConstructor
@Transactional
public class TagService {

    private final TagRepository tagRepository;

    private final UserRepository userRepository;

    public Long save(final Long userId, final TagCreateRequest tagCreateRequest) {
        final User user = userRepository.findById(userId)
                .orElseThrow(() -> new BadRequestException(NOT_FOUND_USER));

        if (checkDuplicateTagName(user.getId(), tagCreateRequest.getName())) {
            throw new BadRequestException(DUPLICATED_TAG_NAME);
        }

        final Tag createdTag = Tag.builder()
                .name(tagCreateRequest.getName())
                .user(user)
                .createdAt(LocalDateTime.now())
                .build();

        Tag tag = tagRepository.save(createdTag);

        return tag.getId();
    }
}

 
์ด์ œ TagService์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด์ž. TagService๊ฐ€ save()ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ–ˆ์„ ๋•Œ, ์ €์žฅ๋œ ํƒœ๊ทธ์˜ id๋ฅผ ์ œ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š”์ง€ ํ™•์ธํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.
TagService๋Š” ์Šคํ”„๋ง์œผ๋กœ๋ถ€ํ„ฐ TagRepository์™€ UserRepository๋ฅผ ์ฃผ์ž…๋ฐ›๊ณ  ์žˆ๋‹ค. 

(1) Junit๊ณผ Mockito ๊ฒฐํ•ฉํ•˜๊ธฐ

@ExtendWith(MockitoExtension.class)
class TagServiceTest {
	...
}

 
๋จผ์ € Mockito์™€ Junit์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค ์œ„์— @ExtendWith(MockitoExtension.class) ์• ๋…ธํ…Œ์ด์…˜์„ ๋‹ฌ์•„์ค€๋‹ค.
 

(2) ๊ฐ€์งœ ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐ ์ฃผ์ž…ํ•˜๊ธฐ

@ExtendWith(MockitoExtension.class)
class TagServiceTest {

    @InjectMocks
    private TagService tagService;

    @Mock
    private TagRepository tagRepository;

    @Mock
    private UserRepository userRepository;
    
}

 
์ด๋ ‡๊ฒŒ ํ…Œ์ŠคํŠธ์— ํ•„์š”ํ•œ ๊ฐ์ฒด๋“ค์„ ์„ ์–ธํ•ด์ค€๋‹ค.
 
- @InjectMocks: ํ…Œ์ŠคํŠธํ•  ๊ฐ์ฒด๊ฐ€ ๊ฐ€์งœ ๊ฐ์ฒด๋ฅผ ์ฃผ์ž…๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” tagService์— ๋ถ™์—ฌ์ฃผ์—ˆ๋‹ค.
- @Mock: ๊ฐ€์งœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๋Š” ์• ๋…ธํ…Œ์ด์…˜์ด๋‹ค. ์ด์ œ tagService๋Š” ๊ฐ€์งœ tagRepository์™€ ๊ฐ€์งœ userRepository๋ฅผ ์ฃผ์ž…๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.
 
 

(3) ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ ์ž‘์„ฑ

tagService๊ฐ€ ์‹ค์ œ๋กœ save() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœ๋ฐ›์•˜์„ ๋•Œ, ์ €์žฅํ•œ ํƒœ๊ทธ์˜ id๋ฅผ ์ž˜ ๋ฆฌํ„ดํ•˜๋Š”์ง€๋ฅผ ํ…Œ์ŠคํŠธํ•ด๋ณด์ž.
 

static Tag COMPANY_TAG = Tag.builder()
                	.id(1L)
                	.name("ํšŒ์‚ฌ")
                	.createdAt(LocalDateTime.now())
               		.build();
                    
static User USER_KIM = User.builder()
                	.id(2L)
                	.email("siltarae@nn.com")
                	.createdAt(LocalDateTime.now())
                	.nickname("Kim")
                	.socialType(SocialType.GOOGLE)
                	.build();

 
๋จผ์ € ํ…Œ์ŠคํŠธ์šฉ ๋ฐ์ดํ„ฐ๋ฅผ ์ค€๋น„ํ•œ๋‹ค.
์—ฌ๊ธฐ์„œ๋Š” ํšŒ์‚ฌ ํƒœ๊ทธ์™€, ์ด๋ฆ„์ด Kim์ธ ์‚ฌ์šฉ์ž๋ฅผ ์ค€๋น„ํ–ˆ๋‹ค.
 

@Test
void ํƒœ๊ทธ_์ƒ์„ฑ_ํ›„_tagId๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() {
    // given
    final TagCreateRequest tagCreateRequest = new TagCreateRequest(COMPANY_TAG.getName());
    given(userRepository.findById(2L))
            .willReturn(Optional.ofNullable(USER_KIM));
    given(tagRepository.save(any(Tag.class)))
            .willReturn(COMPANY_TAG);

    // when
    final Long actualId = tagService.save(2L, tagCreateRequest);

    // then
    assertThat(actualId).isEqualTo(1L);
}

 
์ด์ œ stubbing์„ ํ•  ์ฐจ๋ก€์ด๋‹ค. stubbing์ด๋ž€, ๊ฐ€์งœ ๊ฐ์ฒด์˜ ํŠน์ • ํ–‰๋™์„ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์ธ๋ฐ, ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์„ ํ™•์‹คํžˆ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.
 
๋งŒ์•ฝ userRepository๊ฐ€ ์—‰๋šฑํ•˜๊ฒŒ ํ–‰๋™ํ•˜๋ฉด? ์œ„ ํ…Œ์ŠคํŠธ๋Š” ์‹คํŒจํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ๋ฏธ๋ฆฌ ๊ฐ€์งœ ๊ฐ์ฒดํ•œํ…Œ '๋„ˆ ์ด ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ๋˜๋ฉด ์ด๋ ‡๊ฒŒ ํ–‰๋™ํ•ด์•ผํ•ด. ์•Œ์•˜์ง€?' ๋ผ๊ณ  ์ผ๋Ÿฌ๋‘๋Š” ๊ฒƒ์ด๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” BDD ๊ตฌ์กฐ์— ๋งž์ถ”์–ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก BDDMockito๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค. 
 
given()์€ ์–ด๋–ค ๊ฐ์ฒด๊ฐ€ ์–ด๋–ค ๋ช…๋ น์„ ๋ฐ›์•˜์„ ๋•Œ๋ฅผ ์ง€์ •ํ•œ๋‹ค. ์œ„์—์„œ userRepository๋Š” id=2์ธ User๋ฅผ ์ฐพ์œผ๋ผ๋Š” ๋ช…๋ น์„ ๋ฐ›์•˜์„ ๋•Œ๋ฅผ ์ง€์ •๋ฐ›์•˜๋‹ค.
๊ทธ๋ฆฌ๊ณ  willReturn()์„ ํ†ตํ•ด ํ•ด๋‹น ์ƒํ™ฉ์—์„œ ์–ด๋–ค ๊ฐ’์„ ๋ฐ˜ํ™˜ํ• ์ง€๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. userRepository๋Š” ํ•ด๋‹น ์ƒํ™ฉ์—์„œ ํ•ญ์ƒ USER_KIM์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

๐Ÿ’ก BDDMockto๋ž€?
Mockito๋ฅผ BDD ๊ตฌ์กฐ์— ๋งž์ถฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ™•์žฅํ•œ ๊ฒƒ. ๊ธฐ๋Šฅ์˜ ์ฐจ์ด๋Š” ์—†์ง€๋งŒ, ๊ฐ€๋…์„ฑ์ด ํ–ฅ์ƒ๋œ ๋ฉ”์„œ๋“œ๋ช…์„ ์ œ๊ณตํ•œ๋‹ค.

 
 
when ์ ˆ์—์„œ๋Š” ์‹ค์ œ tagService์˜ save() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ๋’ค, ๊ฒฐ๊ณผ๋กœ ๋ฐ˜ํ™˜๋œ ๊ฐ’์„ ๋ฐ›์•„์˜จ๋‹ค.
๋งˆ์ง€๋ง‰์œผ๋กœ then ์ ˆ์—์„œ ๋ฐ˜ํ™˜๊ฐ’์ด 1์ด ๋งž๋Š”์ง€๋ฅผ ์ฒดํฌํ•˜๋ฉด ํ…Œ์ŠคํŠธ๊ฐ€ ๋๋‚œ๋‹ค.

(4) ์‹คํ–‰ ๊ฒฐ๊ณผ ํ™•์ธ

 


4. ์ฐธ๊ณ ์ž๋ฃŒ

Mockito Tutorial
https://mangkyu.tistory.com/145 

WebMvcTest docs

'๐’๐ฉ๐ซ๐ข๐ง๐ ' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Spring์—์„œ ๊ตฌ๊ธ€ ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ตฌํ˜„ํ•˜๊ธฐ (2) - FeignClient(OpenFeign)์„ ์ด์šฉํ•ด ์•ก์„ธ์Šค ํ† ํฐ ๋ฐ›์•„์˜ค๊ธฐ  (0) 2023.12.24
Spring์—์„œ ๊ตฌ๊ธ€ ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ตฌํ˜„ํ•˜๊ธฐ (1) - ํด๋ผ์ด์–ธํŠธ ๋“ฑ๋ก  (1) 2023.12.24
  1. 1. Mockito๋ž€?
  2. 2. ์ปจํŠธ๋กค๋Ÿฌ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ 
  3. (1) @WebMvcTest๋ฅผ ํ†ตํ•ด ์›น ๊ณ„์ธต ํ…Œ์ŠคํŠธ ์ค€๋น„
  4. (2) ํ•„์š”ํ•œ ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐ ์ฃผ์ž…ํ•˜๊ธฐ
  5. (3) ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ ์ž‘์„ฑ
  6. (4) ์‹คํ–‰ ๊ฒฐ๊ณผ ํ™•์ธ
  7. 3. ์„œ๋น„์Šค ๋‹จ์œ„ ํ…Œ์ŠคํŠธ
  8. (1) Junit๊ณผ Mockito ๊ฒฐํ•ฉํ•˜๊ธฐ
  9. (2) ๊ฐ€์งœ ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐ ์ฃผ์ž…ํ•˜๊ธฐ
  10. (3) ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ ์ž‘์„ฑ
  11. (4) ์‹คํ–‰ ๊ฒฐ๊ณผ ํ™•์ธ
  12. 4. ์ฐธ๊ณ ์ž๋ฃŒ
'๐’๐ฉ๐ซ๐ข๐ง๐ ' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • Spring์—์„œ ๊ตฌ๊ธ€ ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ตฌํ˜„ํ•˜๊ธฐ (2) - FeignClient(OpenFeign)์„ ์ด์šฉํ•ด ์•ก์„ธ์Šค ํ† ํฐ ๋ฐ›์•„์˜ค๊ธฐ
  • Spring์—์„œ ๊ตฌ๊ธ€ ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ตฌํ˜„ํ•˜๊ธฐ (1) - ํด๋ผ์ด์–ธํŠธ ๋“ฑ๋ก
gorapaduckoo
gorapaduckoo
gorapaduckoo
์ง„ํ™”์˜ ๋Œ
gorapaduckoo
์ „์ฒด
์˜ค๋Š˜
์–ด์ œ
  • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ
    • ๐€๐ฅ๐ ๐จ๐ซ๐ข๐ญ๐ก๐ฆ
    • ๐‚๐’
      • ๐‰๐š๐ฏ๐š
      • ๐ƒ๐š๐ญ๐š๐›๐š๐ฌ๐ž
      • ๐๐ž๐ญ๐ฐ๐จ๐ซ๐ค
      • ๐„๐ญ๐œ.
    • ๐’๐ฉ๐ซ๐ข๐ง๐ 
      • ๐๐š๐ฌ๐ข๐œ
      • ๐Œ๐•๐‚ (๐Ÿ)
      • ๐’๐ž๐œ๐ฎ๐ซ๐ข๐ญ๐ฒ
    • ๐๐ซ๐จ๐ฃ๐ž๐œ๐ญ๐ฌ
      • ๐‘๐ž๐œ๐จ๐ฎ๐ซ๐ญ๐š
      • ๐’๐ข๐ฅ๐ญ๐š๐ซ๐š๐ž
    • ๐†๐ข๐ญ
    • ๐‘๐ž๐ฏ๐ข๐ž๐ฐ
    • ๐’๐ญ๐ฎ๐๐ฒ

๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

  • ํ™ˆ
  • ํƒœ๊ทธ
  • ๋ฐฉ๋ช…๋ก

๊ณต์ง€์‚ฌํ•ญ

์ธ๊ธฐ ๊ธ€

ํƒœ๊ทธ

  • ๋„คํŠธ์›Œํฌ
  • http
  • Union-FInd
  • BOJ
  • ์•Œ๊ณ ๋ฆฌ์ฆ˜
  • aop
  • ๋ธŒ๋ฃจํŠธํฌ์Šค
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค
  • IOC
  • ๋ฝ
  • ์—๋“œ๋ชฌ๋“œ-์นดํ”„
  • ํŠธ๋ฆฌ
  • mvc ํŒจํ„ด
  • DI
  • OOP
  • ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค
  • spring
  • DFS
  • Spring ๊ธฐ๋ณธํŽธ
  • ๋ฐฑ์ค€
  • ๋น„ํŠธ๋งˆ์Šคํ‚น
  • dp
  • web
  • ๊ตฌํ˜„
  • spring mvc
  • CS

์ตœ๊ทผ ๋Œ“๊ธ€

์ตœ๊ทผ ๊ธ€

hELLO ยท Designed By ์ •์ƒ์šฐ.v4.2.2
gorapaduckoo
Mockito๋ฅผ ์ด์šฉํ•œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”

๋‹จ์ถ•ํ‚ค

๋‚ด ๋ธ”๋กœ๊ทธ

๋‚ด ๋ธ”๋กœ๊ทธ - ๊ด€๋ฆฌ์ž ํ™ˆ ์ „ํ™˜
Q
Q
์ƒˆ ๊ธ€ ์“ฐ๊ธฐ
W
W

๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๊ธ€

๊ธ€ ์ˆ˜์ • (๊ถŒํ•œ ์žˆ๋Š” ๊ฒฝ์šฐ)
E
E
๋Œ“๊ธ€ ์˜์—ญ์œผ๋กœ ์ด๋™
C
C

๋ชจ๋“  ์˜์—ญ

์ด ํŽ˜์ด์ง€์˜ URL ๋ณต์‚ฌ
S
S
๋งจ ์œ„๋กœ ์ด๋™
T
T
ํ‹ฐ์Šคํ† ๋ฆฌ ํ™ˆ ์ด๋™
H
H
๋‹จ์ถ•ํ‚ค ์•ˆ๋‚ด
Shift + /
โ‡ง + /

* ๋‹จ์ถ•ํ‚ค๋Š” ํ•œ๊ธ€/์˜๋ฌธ ๋Œ€์†Œ๋ฌธ์ž๋กœ ์ด์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ํ‹ฐ์Šคํ† ๋ฆฌ ๊ธฐ๋ณธ ๋„๋ฉ”์ธ์—์„œ๋งŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.