2 λΆ„ μ†Œμš”

1.μš”μ•½

λ‹¨μœ„ ν…ŒμŠ€νŠΈλ₯Ό μž‘μ„±ν•˜λ‹€κ°€ λ‚―μ„  μ˜ˆμ™Έμ— λ§ˆμ£Όμ³€λ‹€.

ν•΄λ‹Ή μ˜ˆμ™Έ 클래슀의 description 을 ν™•μΈν•œ κ²°κ³Ό, mockito ν”„λ ˆμž„μ›Œν¬μ˜ strictness 레벨 섀정에 κ΄€ν•œ μ΄μŠˆκ°€ μžˆμ–΄ ν…ŒμŠ€νŠΈκ°€ μ‹€νŒ¨ν•˜κ³  μžˆμ—ˆλ‹€.

strictness μ„€μ •μ΄λž€, μš”μ•…ν•˜μžλ©΄ λΆˆν•„μš”ν•œ stubbing 을 ν—ˆμš©ν• μ§€ 말지에 λŒ€ν•œ μ˜΅μ…˜μ΄λ‹€. κΈ°λ³Έ 레벨이 STRICT_STUBS이며, LENIENT으둜 μˆ˜μ •ν•΄μ£Όμ–΄μ•Ό μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” stub 에 λŒ€ν•΄ λ¬΄μ‹œν•˜κ³  톡과할 수 μžˆλ‹€.

즉 stubbing κ΄€λ ¨ λ‘œμ§μ„ BeforeEach λ©”μ„œλ“œμ— λ³„λ„λ‘œ μ •λ¦¬ν•˜μ˜€λŠ”λ° 이 mocking을 μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” ν…ŒμŠ€νŠΈκ°€ μ‘΄μž¬ν•˜μ—¬ λ°œμƒν•˜λŠ” μ—λŸ¬μ˜€λ‹€.

2.상황

예λ₯Ό λ“€μ–΄ νšŒμ›μ— κ΄€ν•˜μ—¬ μ „ν™”λ²ˆν˜Έ 쀑볡 체크 Validation 을 μ²˜λ¦¬ν•˜λŠ” μ„œλΉ„μŠ€ 둜직이 있고, ν•΄λ‹Ή validator λ‚΄λΆ€μ˜ Repository 클래슀λ₯Ό mocking ν•˜μ—¬ λ‹¨μœ„ν…ŒμŠ€νŠΈλ₯Ό μž‘μ„±ν•œλ‹€κ³  κ°€μ •ν•΄λ³΄μž.

  • MemberValidator.java
1
2
3
4
5
6
7
8
9
private final MemberRepository repository;

public void duplicateCheck(SearchCondition cond) {

    repository.findOne(cond)
        .ifPresent(m -> {
            throw new IllegalStateException("Duplicated Memberr");
        });
}
  • ValidatorTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Mock
MemberRepository repository;
@InjectMocks
MemberValidator validator;

@BeforeEach
void setUp() {
    
    SearchCondition cond = new SearchCondition("01012345678");
    SearchCondition wrongCond = new SearchCondition("01056781234");
    
    Member givenMember = Member.builder()
        .name("test_member")
        .mobile("01012345678")
        .build();

    doReturn(Optional.of(givenMember)).when(repository).findOne(cond);
    doReturn(Optional.empty()).when(repository).findOne(wrongCond);
}

@Test
void notDuplicated() {
    Member member = Member.builder()
            .mobile("01056781234")
            .build();

    assertDoesNotThrow(() -> validator.duplicateCheck(member));
}

@Test
void duplicated() {
    Member member = Member.builder()
            .mobile("01012345678")
            .build();

    assertThrows(IllegalStateException.class, 
        () -> validator.duplicateCheck(member));
}
  • duplicated ν…ŒμŠ€νŠΈλŠ” cond 검색 쑰건으둜 stub 된 λ°˜ν™˜ 값을 μ‚¬μš©ν•˜κ³  μžˆλ‹€.
  • notDuplicated ν…ŒμŠ€νŠΈλŠ” wrongCond 검색 쑰건으둜 stub 된 λ°˜ν™˜ 값을 μ‚¬μš©ν•˜κ³  μžˆλ‹€.

κ·Έλ ‡λ‹€λ©΄ 각 ν…ŒμŠ€νŠΈλŠ” μ‹€ν–‰ μ „ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” stubbing 을 1νšŒμ”© μ‹€μ‹œν•˜κ³  μžˆλŠ” 것이닀.

3.ν•΄κ²°

μœ„ 상황을 ν•΄κ²°ν•΄μ£ΌκΈ° μœ„ν•΄μ„œλŠ” λ‹€μŒκ³Ό 같은 방법듀이 μ‘΄μž¬ν•œλ‹€.

1) mock strict level 을 μ‘°μ ˆν•œλ‹€.

1-1. @Mock μ• λ…Έν…Œμ΄μ…˜μ— lenient 값을 쀄 수 μžˆλ‹€.

1
2
3
4
@Mock(lenient = true)
MemberRepository repository;
@InjectMocks
MemberValidator validator;

1-2. stub λ‹¨μœ„λ³„λ‘œ lenient() λ©”μ„œλ“œ 체이닝을 톡해 Β lenient λ ˆλ²¨μ„ μ‘°μ •ν•  수 μžˆλ‹€.

1
2
lenient().doReturn(Optional.of(givenMember)).when(repository).findOne(cond);
lenient().doReturn(Optional.empty()).when(repository).findOne(wrongCond);

2) stub 을 ν…ŒμŠ€νŠΈ λ‹¨μœ„λ³„λ‘œ μ‹€μ‹œν•œλ‹€.

BeforeEach μ˜μ—­μ—μ„œ 곡용으둜 μ‹€μ‹œν•˜λ˜ stubbing 을 ν…ŒμŠ€νŠΈ 별 ν•„μš”ν•œ stubbing 만 μ§„ν–‰ν•˜λ„λ‘ κ°œμ„ ν•œλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@Mock
MemberRepository repository;
@InjectMocks
MemberValidator validator;    

@Test
void notDuplicated() {
    //given
    SearchCondition wrongCond = new SearchCondition("01056781234");
    doReturn(Optional.empty()).when(repository).findOne(wrongCond);
    
    //when   
    Member member = Member.builder()
            .mobile("01056781234")
            .build();
    
    //then
    assertDoesNotThrow(() -> validator.duplicateCheck(member));
}

@Test
void duplicated() {
    //given
    SearchCondition cond = new SearchCondition("01012345678");
    Member givenMember = Member.builder()
        .name("test_member")
        .mobile("01012345678")
        .build();
        
    doReturn(Optional.of(givenMember))
        .when(repository).findOne(cond);     
        
    //when
    Member member = Member.builder()
            .mobile("01012345678")
            .build();
            
    //then                
    assertThrows(IllegalStateException.class, 
        () -> validator.duplicateCheck(member));
}

4.κ²°λ‘ 

ν…ŒμŠ€νŠΈ μ½”λ“œμ˜ 엄격성 (Strictness) λŠ” mockito ν”„λ ˆμž„μ›Œν¬ 2.x 버전뢀터 λ„μž… 된 κΈ°λŠ₯이라고 ν•œλ‹€. Β μ΄λŠ” ν…ŒμŠ€νŠΈ μ½”λ“œμ—μ„œ λΆˆν•„μš”ν•œ stub 및 쀑볡 μ½”λ“œλ₯Ό μ œκ±°ν•˜κΈ° μœ„ν•¨μΈλ°, 보톡 이런 경우 μ–΅μ§€λ‘œ strictness λ ˆλ²¨μ„ μ‘°μ •ν•˜κΈ° 보닀 ν”„λ ˆμž„μ›Œν¬ 철학에 λ§žμΆ”μ–΄ 섀계λ₯Ό μˆ˜μ •ν•˜λŠ” 편이 쒋은 μ½”λ“œλ₯Ό μž‘μ„±ν•˜λŠ” 방법이 μ•„λ‹κΉŒ μƒκ°ν•œλ‹€.

νƒœκ·Έ: ,

μΉ΄ν…Œκ³ λ¦¬:

μ—…λ°μ΄νŠΈ: