JiwonDev

ํ…Œ์ŠคํŠธ ๋ชจํ‚น Mockito ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

by JiwonDev

2021.09.07 - [Backend/Java] - ๋‹ค์–‘ํ•œ ํ…Œ์ŠคํŠธ์™€ Test Double (+Mockist)

 

๋‹ค์–‘ํ•œ ํ…Œ์ŠคํŠธ์™€ Test Double (+Mockist)

Mockito ๋ ˆํผ๋Ÿฐ์Šค https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html Mockito - mockito-core 3.12.4 javadoc Latest version of org.mockito:mockito-core https://javadoc.io/d..

jiwondev.tistory.com

 

# Mockito๋ž€?

https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html

ํ…Œ์ŠคํŠธ์— ํ•„์š”ํ•œ Mock Object๋ฅผ ์ƒ์„ฑ, ๊ฒ€์ฆ, ์Šคํ„ฐ๋น™(Creation, Verification, Stubbing)ํ•ด์ฃผ๋Š” ์ž๋ฐ” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค.

gradle์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

โžก ๋ณดํ†ต Junit, AssertJ, Mockito๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•œ๋‹ค.

dependencies {
    testImplementation('org.junit.jupiter:junit-jupiter:5.6.0')
    testImplementation('org.assertj:assertj-core:3.11.1')
    testImplementation('org.mockito:mockito-core:3.3.0')
}

 

์Šคํ”„๋ง์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, ์Šคํ”„๋ง ๋ถ€ํŠธ ํ…Œ์ŠคํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— Mockito๊ฐ€ ์ด๋ฏธ ํฌํ•จ๋˜์–ด์žˆ์–ด ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฐธ๊ณ ๋กœ ์Šคํ”„๋งํ…Œ์ŠคํŠธ์—” Junit, assertj, hamcrest, xmlunit ๋“ฑ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ํ…Œ์ŠคํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋„ ํฌํ•จ๋˜์–ด์žˆ๋‹ค.

testImplementation 'org.springframework.boot:spring-boot-starter-test'

# 1. ๊ธฐ๋ณธ ๋™์ž‘ (์ƒ์„ฑ-๊ฒ€์ฆ-์Šคํ„ฐ๋น™)

์ž๋ฐ”์˜ ๊ฐ์ฒด๋ฅผ mock(...) ๋ฉ”์„œ๋“œ๋กœ Stubingํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ Stubing ํ•œ ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•ด ๋‹ค์–‘ํ•œ Mocking์„ ๋งŒ๋“ ๋‹ค.

import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;

class EX1_Mockito {
    @Test
    void stubbing() throws Exception{
        // 1. Mock ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•จ.
        List<String> mockedList = mock(ArrayList.class);

        // 2. when์„ ์ด์šฉํ•œ stubbing. ๊ฐ€์งœ ๋™์ž‘์„ ์ง€์ •ํ•จ.
        when(mockedList.get(0)).thenReturn("First");
        when(mockedList.get(1)).thenThrow(new IndexOutOfBoundsException());

        // 3-1 Junit์ด๋‚˜ AssertJ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๋™์ž‘์„ ํ•˜๋Š”์ง€ ํ™•์ธํ•จ.
        assertThat(mockedList.get(0)).isEqualTo("First"); // ๋ฐ˜ํ™˜๊ฐ’์ด First์ธ๊ฐ€?
        assertThatThrownBy(() -> mockedList.get(1)) // ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋Š” 
                .isInstanceOf(IndexOutOfBoundsException.class); // ์ด ์˜ˆ์™ธ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”๊ฐ€?

        assertThat(mockedList.get(10)).isNull(); // ํ•ด๋‹น ๋ฉ”์„œ๋“œ์˜ ๊ฒฐ๊ณผ๊ฐ€ Null์ธ๊ฐ€?

        // 3-2 ๋ฐ˜ํ™˜๊ฐ’์ด ์—†๋Š” ๊ฒฝ์šฐ. ํ•ด๋‹น ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€๋„ ํ™•์ธ๊ฐ€๋Šฅํ•˜๋‹ค.
        // ํŒŒ๋ผ๋ฏธํ„ฐ๋„ ๊ฒ€์ฆํ•œ๋‹ค. verify(mockedList).get(2); ๋งŒ ํ˜ธ์ถœ๋˜์—ˆ๋‹ค๋ฉด ์‹คํŒจ!
        verify(mockedList, times(1)).get(0);
        verify(mockedList).get(0); // ์ƒ๋žต์‹œ 1๋ฒˆ
    }
}

 

์ฐธ๊ณ ๋กœ verify๋Š” BDD Mockito๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฉ”์„œ๋“œ ์ด๋ฆ„๋งŒ ๋‹ค๋ฅผ ๋ฟ, ๋™์ž‘์€ ๋‚ด๋ถ€ ๋™์ž‘์€ ๋น„์Šทํ•˜๋‹ค.

@Test
void startBDDStyle(){
    //Given
    Study study = new Study("test", 10);
    Member member = new Member();
    member.setEmail("delusidiot@gmail.com");
    member.setId(1L);
 
    BDDMockito.given(memberServiceMock.findById(1L)).willReturn(Optional.of(member));
    BDDMockito.given(repositoryMock.save(study)).willReturn(study);
    StudyService studyService = new StudyService(memberServiceMock, repositoryMock);
 
    //When
    studyService.createNewStudy(1L, study);
 
    //Then
 
    BDDMockito.then(memberServiceMock).should(times(1)).notify(study);
    BDDMockito.then(memberServiceMock).should().notify(member); // ์ƒ๋žต์‹œ 1๋ฒˆ
    BDDMockito.then(memberServiceMock).shouldHaveNoInteractions();
    // ์ฐธ๊ณ ๋กœ ํŠน์ • ์‹œ์  ์ดํ›„๋กœ ์ธํ„ฐ๋ ‰์…˜์ด ์—†๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ..NoMoreInteraction()๋ฅผ ์“ฐ์ž
}

 

 

# 2. Argument Matcher

Mockito๋Š” ๋‹ค์–‘ํ•œ ArgumentMatcher๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ’ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋…ผ๋ฆฌ์ ์ธ ํƒ€์ž…์œผ๋กœ ์Šคํ„ฐ๋น™ ๊ฐ€๋Šฅํ•˜๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด AnyInt(), AnyString()์„ ํŒŒ๋ผ๋ฏธํ„ฐ์— ์ „๋‹ฌํ•ด์„œ ํ•ด๋‹น ํƒ€์ž…์„ ์ฃผ์—ˆ์„ ๋•Œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”์ง€ ๊ฒ€์ฆ๊ฐ€๋Šฅํ•˜๋‹ค.

@Test
void argument_matchers() throws Exception{
    List<String> mockedList = mock(ArrayList.class);

    when(mockedList.get(anyInt())).thenReturn("AnyInt");

    assertThat(mockedList.get(1010)).isEqualTo("AnyInt");

    verify(mockedList).get(anyInt()); // verify๋„ ์‚ฌ์šฉ๊ฐ€๋Šฅ!
}

๋ฌผ๋ก  ํ•„์š”ํ•˜๋‹ค๋ฉด ๋…ผ๋ฆฌ์ ์ธ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ArgumentMatcher๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•ด์„œ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ๋“ค์–ด๊ฐˆ ์ž๋ฆฌ์— argThat ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์„œ ์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
@Test
void matcherSupport() throws Exception {
    final List<String> mockedList = mock(List.class);
    mockedList.add("Hello");
    mockedList.add("Dexter");
    mockedList.add("James");
	
    // when์—์„œ anyInt() ๋Œ€์‹ ์— any[ํฌ๊ธฐ๊ฐ€ 3 ์ดํ•˜์ธ ๋ฆฌ์ŠคํŠธ]๋ฅผ ๋„ฃ๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ
    when(mock.someMethod(argThat(list -> list.size()<3))).thenReturn(null);
    
    // verify๋„ ๋˜‘๊ฐ™์ด ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค. ๊ทธ๋ƒฅ ๋ฉ”์„œ๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ์ž๋ฆฌ์— argThat์„ ๋งŒ๋“ค๋ฉด ๋จ.
    verify(mockedList, times(3))
            .add( // add(..) ๋ฉ”์„œ๋“œ์— ๋“ค์–ด๊ฐ„ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์˜ ๊ธธ์ด๊ฐ€ 3์ดˆ๊ณผ, 8๋ฏธ๋งŒ์ž„์„ ๊ฒ€์ฆํ•จ
                    argThat(string -> (string.length() < 8) && (string.length() > 3))
            );
}

๋ฌผ๋ก  Java8์˜ ๋žŒ๋‹ค์‹ ๋Œ€์‹ ์— ์ต๋ช… ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์…”๋„ ๋ฉ๋‹ˆ๋‹ค.

 // JAVA 8 ๋žŒ๋‹ค๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•
 verify(list, times(2)).add(argThat(string -> string.length() < 5));

 // JAVA 7 ์ต๋ช… ํด๋ž˜์Šค๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•
 verify(list, times(2)).add(argThat(new ArgumentMatcher(){
     public boolean matches(String arg) {
         return arg.length() < 5;
     }
 }));

 // ๊ฐ์ฒด๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›๋Š” ๊ฒฝ์šฐ, receiveComplexObject๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ์ฒด ๊ฒ€์ฆ๊ฐ€๋Šฅ.
 verify(target, times(1)).receiveComplexObject(
                                 argThat( obj -> obj.getSubObject().get(0).equals("expected") )
                                 );

 

# 3. verify ์ถ”๊ฐ€ ๊ธฐ๋Šฅ

verify๋Š” ๋ณดํ†ต ํ•ด๋‹น ๊ธฐ๋Šฅ์ด ์‚ฌ์šฉ๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๊ฒ€์ฆํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ์ถ”๊ฐ€์ ์ธ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ฃผ๋ฉด ํ•ด๋‹น ๊ธฐ๋Šฅ์ด ๋ช‡๋ฒˆ ์‚ฌ์šฉ๋˜์—ˆ๋Š”์ง€, ํ•œ๋ฒˆ๋„ ์‚ฌ์šฉ๋˜์ง€ ์•Š์•˜๋Š”์ง€๋„ ๊ฒ€์ฆ ๊ฐ€๋Šฅํ•˜๋‹ค.

@Test
void verify_mockito() throws Exception{
    List<String> mockedList = mock(ArrayList.class);

    mockedList.add("once");

    mockedList.add("twice");
    mockedList.add("twice");

    mockedList.add("three times");
    mockedList.add("three times");
    mockedList.add("three times");

    // 1. add("once")๊ฐ€ ๋ช‡๋ฒˆ ํ˜ธ์ถœ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
    verify(mockedList).add("once"); // time(1)์€ ๊ธฐ๋ณธ๊ฐ’์ด๋ผ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ๋‹ค.
    verify(mockedList, time(1)).add("once");
    verify(mockedList, times(2)).add("twice");
    verify(mockedList, times(3)).add("three times");

    // 2. ๊ทธ ์™ธ ๋‹ค์–‘ํ•œ ์ถ”๊ฐ€ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ œ๊ณตํ•œ๋‹ค. never()๋Š” ํ•œ๋ฒˆ๋„ ํ˜ธ์ถœ๋˜์ง€ ์•Š์€๊ฒฝ์šฐ OK
    verify(mockedList, atLeastOnce()).add("once");
    verify(mockedList, atMostOnce()).add("once");
    verify(mockedList, atLeast(1)).add("twice");
    verify(mockedList, atMost(10)).add("three times");
    verify(mockedList, never()).add("mockito");
}

 

## any, ํŠน์ • ํƒ€์ž…์ด ์‚ฌ์šฉ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ(์ž์‹, ์ƒ์†๋“ฑ)

์ฐธ๊ณ ๋กœ ์ž…๋ ฅ๊ฐ’์ด ์•„๋‹ˆ๋ผ ํŠน์ • ํƒ€์ž…์ธ์ง€ ๊ฒ€์‚ฌํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ any๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

์œ„์—์„œ ์„ค๋ช…ํ•œ Argument Matcher๋ฅผ ํ†ตํ•ด ํƒ€์ž…์„ ๊ฒ€์‚ฌํ•œ๋‹ค. ๋‹จ ๊ธฐ๋ณธํ˜•์€ ํƒ€์ž… ๋ณ€ํ™˜์ด ๋ถˆ๊ฐ€๋Šฅํ•ด์„œ, anyInt() ๊ฐ™์€ ๊ฑธ ์‚ฌ์šฉํ•ด Integer๋กœ ์—…์บ์ŠคํŒ…ํ•ด์„œ ํƒ€์ž…์„ ๊ฒ€์‚ฌํ•œ๋‹ค.

verify(mockedList).add(any()); // ์ž…๋ ฅ๊ฐ’์ด Object๋กœ ๋ณ€ํ™˜ ๊ฐ€๋Šฅํ•œ๊ฐ€? (primitive ํƒ€์ž… ๋ฏธํฌํ•จ)
verify(mockedList).add(any(MyClass.class)); // ์ž…๋ ฅ๊ฐ’์ด MyClass.class๋กœ ๋ณ€ํ™˜๊ฐ€๋Šฅํ•œ๊ฐ€?
verify(bar).doPrimitiveStuff(anyInt()); // ์ž…๋ ฅ๊ฐ’์ด Integer๋กœ ๋ณ€ํ™˜ ๊ฐ€๋Šฅํ•œ๊ฐ€?
@MockBean
private JavaMailSender mockMailSender;

// mockMailSender.send( ..ํ•ด๋‹น ํƒ€์ž….. ) ๋ฉ”์„œ๋“œ๊ฐ€ 1๋ฒˆ ์‹คํ–‰๋˜์—ˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•œ๋‹ค.
verify(mockMailSender).send( any(SimpleMailMessage.class) );

then(mockMailSender).should().send( any(SimpleMailMessage.class) );

์˜›๋‚ ์— ๋งŒ๋“ค์–ด์ง„ isA(..) ๋ฉ”์„œ๋“œ๋„ ์žˆ๋Š”๋ฐ, ์ด๋ฆ„์ด ์• ๋งคํ•ด์„œ any(), anyString()์œผ๋กœ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค. (๊ธฐ๋Šฅ์€ ๊ฐ™๋‹ค)

 

 

# 4. void method ์˜ˆ์™ธ ์Šคํ„ฐ๋น™

๋ฐ˜ํ™˜๊ฐ’์ด void์ธ ๊ฒฝ์šฐ Mockito.when( ).method... ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์–ด ๋‹ต๋‹ตํ•˜๋‹ค. โžก ์ด ๋•Œ๋Š” doThorw, doNothing ์‚ฌ์šฉ

@Test
void doThrow_mockito() throws Exception {
    List<String> mockedList = mock(ArrayList.class);
	
    // void clear(); ๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๋„๋ก Stubingํ•œ๋‹ค.
    doThrow(new RuntimeException("Boom!")).when(mockedList).clear();

    // clear ๋ฉ”์„œ๋“œ๊ฐ€ ์˜ˆ์™ธ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”์ง€ ๊ฒ€์ฆ
    assertThatThrownBy(() -> mockedList.clear())
            .isInstanceOf(RuntimeException.class)
            .hasMessage("Boom!");
            
            
    // ์•„๋‹ˆ๋ฉด doNothing()์„ ์‚ฌ์šฉํ•ด๋„ ๋œ๋‹ค.
     Person p = mock(Person.class);

     doNothing().when(p).setName("mike");
     p.setName("mike");
     verify(p).setName("mike");
}

 

 

# 5. ํ˜ธ์ถœ๋œ ์ˆœ์„œ ๊ฒ€์ฆํ•˜๊ธฐ - inOrder

@Test
void verify_in_order() throws Exception {
    List<String> firstMockedList = mock(ArrayList.class);
    List<String> secondMockedList = mock(ArrayList.class);

    firstMockedList.add("firstMockList add first");
    firstMockedList.add("firstMockList add second");

    secondMockedList.add("secondMockList add first");
    secondMockedList.add("secondMockList add second");

    // 1. inOrder๋กœ Mock ๊ฐ์ฒด๋ฅผ ๋ฌถ์–ด์„œ ๋ฉ”์„œ๋“œ์˜ ํ˜ธ์ถœ ์ˆœ์„œ๋„ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋‹ค.
    final InOrder inOrder = inOrder(firstMockedList, secondMockedList);

    // 2. ์‚ฌ์šฉ์€ inOrder.verify ๋“ฑ์„ ์ด์šฉํ•˜๋ฉด ๋œ๋‹ค.
    inOrder.verify(firstMockedList).add("firstMockList add first"); // 1๋ฒˆ์จฐ
    inOrder.verify(firstMockedList).add("firstMockList add second"); // 2๋ฒˆ์จฐ
    inOrder.verify(secondMockedList).add("secondMockList add first"); // 3๋ฒˆ์จฐ
    inOrder.verify(secondMockedList).add("secondMockList add second"); // 4๋ฒˆ์งธ
}

 

 

# 6. @Mock Annotaion

Mockito.mock() ์„ ์ด์šฉํ•˜์ง€ ์•Š๊ณ , ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ํŽธํ•˜๊ฒŒ Mock ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

๋‹ค๋งŒ Mockito์˜ ํŠน์„ฑ์ƒ, ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์—†๋Š” ๊ธฐ๋ณธ์ƒ์„ฑ์ž๊ฐ€ ์กด์žฌํ•ด์•ผ Mock ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์ฐธ๊ณ ๋กœ ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด MockitoAnnotation.openMocks(ํ˜„์žฌ ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค)๋ฅผ ๋ฐ˜๋“œ์‹œ ํ•ด์ฃผ์–ด์•ผํ•œ๋‹ค.
    โžก JUnit5 - MockitoJUnitRunner์— ํ•ด๋‹น ๋ฉ”์„œ๋“œ๊ฐ€ ํฌํ•จ๋˜์–ด์žˆ์–ด ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š์•„๋„ ์ƒ๊ด€ ์—†๊ธด ํ•˜๋‹ค.
// Product.java
public class Product {
    private Long id;
    private String name;
    private int price;

    public Product() { // ์ด๊ฑฐ ํ•„์ˆ˜.
    }

    public Product(Long id, String name, int price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    // getters, setters...
}
@Mock private Product product; // ์•Œ์•„์„œ Mock์œผ๋กœ ์ƒ์„ฑ.

@Test
void mockAnnotation() throws Exception{
    // 1. product ์„ ์–ธ๋งŒํ•˜๊ณ  ๋ฐ”๋กœ ์‚ฌ์šฉํ•˜๋ฉด ๋จ.
    MockitoAnnotations.initMocks(this);

    when(product.getId()).thenReturn(3L);

    assertThat(product.getId()).isEqualTo(3L);

    verify(product).getId();
}

 

 

# 7. ์—ฐ์†์œผ๋กœ ์—ฌ๋Ÿฌ๊ฐœ ์Šคํ„ฐ๋น™ํ•˜๊ธฐ

Mock๊ฐ์ฒด์— ๊ฐ€์งœ๊ฐ’์„ ๋“ฑ๋กํ•  ๋•Œ, ํ•œ๋ฒˆ์— ์—ฌ๋Ÿฌ๊ฐœ๋ฅผ ์ฒด์ด๋‹ํ•ด์„œ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋‹ค.

@Test
void consecutive_call() throws Exception{

    // 1. ํ•จ์ˆ˜ ์ฒด์ด๋‹
    List<String> mockedList = mock(List.class);
    when(mockedList.get(0)) // when์€ ํ•ด๋‹น ๋ฉ”์„œ๋“œ๊ฐ€ ๋™์ž‘์„ ๋งˆ์ณค์„ ๋•Œ ๋ฐ˜ํ™˜๊ฐ’์„ ์ง€์ •ํ•œ๋‹ค.
            .thenReturn("Hello") // ๋ฐ˜ํ™˜๊ฐ’ "Hello" ์ง€์ •
            .thenReturn("Dexter") // ์ค‘๋ณตํ•˜๋ฉด ๋ฎ์–ด์”Œ์šฐ๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ, ๋‹ค์Œ ํ˜ธ์ถœ์— ์‚ฌ์šฉ๋œ๋‹ค.
            .thenThrow(new RuntimeException("Boom!")); // ๋ฐœ์ƒํ•  ์˜ˆ์™ธ ์ง€์ •์ง€์ •

    assertThat(mockedList.get(0)).isEqualTo("Hello");
    assertThat(mockedList.get(0)).isEqualTo("Dexter");
    assertThatThrownBy(() -> mockedList.get(0))
            .isInstanceOf(RuntimeException.class)
            .hasMessage("Boom!");


    // 2. ํŒŒ๋ผ๋ฏธํ„ฐ ์ „๋‹ฌ
    List<String> mockedList2 = mock(List.class);
    when(mockedList2.get(0))
            .thenReturn("Hello", "Dexter"); // ์•„๋‹ˆ๋ฉด ์ด๋ ‡๊ฒŒ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ํ•œ๊บผ๋ฒˆ์— ์ค˜๋„ ๋œ๋‹ค.

    assertThat(mockedList2.get(0)).isEqualTo("Hello");
    assertThat(mockedList2.get(0)).isEqualTo("Dexter");


    // 3. ์•„์˜ˆ when์„ ์—ฌ๋Ÿฌ๋ฒˆ ํ˜ธ์ถœ -> ์ด๋Š” ๋ฎ์–ด์”Œ์›Œ์ง„๋‹ค.
    List<String> mockedList3 = mock(List.class);
    when(mockedList3.get(0))
            .thenReturn("Hello");
    when(mockedList3.get(0))
            .thenReturn("Dexter"); // ๊ธฐ์กด์˜ when("Hello")๊ฐ€ ์‚ญ์ œ๋œ๋‹ค.

    assertThat(mockedList2.get(0)).isEqualTo("Dexter");
    assertThat(mockedList2.get(0)).isEqualTo("Dexter");
}

 

 

# 8. Custom ์Šคํ„ฐ๋น™ ๋งŒ๋“ค๊ธฐ

์ด๋ฏธ ์กด์žฌํ•˜๋Š” thenRetun, thenThrow๋งŒ ์‚ฌ์šฉํ•ด๋„ ๋˜์ง€๋งŒ, ํ•„์š”ํ•˜๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ง์ ‘ ๋งŒ๋“ค์ˆ˜๋„์žˆ๋‹ค.

โžก thenAnswer์„ ์ด์šฉํ•ด, ์ต๋ช… ํด๋ž˜์Šค ์ •์˜ or Lambda์‹์„ ์ด์šฉํ•ด์„œ ๊ตฌํ˜„ํ•˜๋ฉด ํŽธํ•˜๋‹ค.

โžก Java์—์„œ๋Š” ๊ฐ์ฒด์˜ ์ถ”์ƒ๋ฉ”์„œ๋“œ๊ฐ€ ๋‹จ 1๊ฐœ์ธ ๊ฒฝ์šฐ, ์•„๋ž˜์™€ ๊ฐ™์ด new ๋ฅผ ์ƒ๋žตํ•˜๊ณ  ๋ฐ”๋กœ ํ•จ์ˆ˜์ฒ˜๋Ÿผ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

// doSomething ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด 12๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์Šคํ„ฐ๋น™
doAnswer(invocation -> 12).when(mock).doSomething();
 
// domSomething(str,str,str) ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด ์ฒซ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ๊ธธ์ด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์Šคํ„ฐ๋น™ 
doAnswer( invocation -> ((String)invocation.getArgument(1)).length() )
     .when(mock)
     .doSomething(anyString(), anyString(), anyString());
@Test
void answer_callback() throws Exception {
    List<String> mockedList = mock(List.class);

    when(mockedList.get(123))
            .thenAnswer(
                    invocation -> { // ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋กœ ๋™์ž‘์ด ๋Œ€์ฒด๋œ๋‹ค.
                        final Object[] arguments = invocation.getArguments();
                        return "์ „๋‹ฌ๋œ ์•„๊ทœ๋จผํŠธ๋“ค: " + Arrays.toString(arguments);
                    }
            );

    assertThat(mockedList.get(123)).isEqualTo("์ „๋‹ฌ๋œ ์•„๊ทœ๋จผํŠธ๋“ค: [123]");
}

 

 

# 9. Spy Mock ๊ฐ์ฒด

์‹ค์ œ ๊ฐ์ฒด์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ๋˜‘๊ฐ™์ด ๋™์ž‘ํ•˜๋Š” Mock์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

=> ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋˜ ๊ฐ’๊นŒ์ง€ ๋˜‘๊ฐ™์ด ๋ณต์‚ฌํ•œ๋‹ค.

@Test
void spy_mock() throws Exception{
    final List<String> nameList = new ArrayList<>();
    final List<String> spy = spy(nameList); // spy ๊ฐ์ฒด ์ƒ์„ฑ

    // 1. ๋น„์–ด์žˆ๋Š” ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ณต์‚ฌํ–ˆ์œผ๋ฏ€๋กœ ๋ถˆ๊ฐ€๋Šฅํ•œ ์Šคํ„ฐ๋น™์ด๋‹ค. (IndexOutOfBoundsException ๋ฐœ์ƒ)
    // when(spy.get(0)).thenReturn("Dexter");
	
    // 1.1 ๋ฌผ๋ก  ์ด๋Ÿฐ๊ฑด ๊ฐ€๋Šฅํ•˜๋‹ค.
    when(spy.size()).thenReturn(100);
    
    // 2. spy ๊ฐ์ฒด๋Š” ์ด๋ ‡๊ฒŒ doReturn์„ ์ด์šฉํ•˜์—ฌ ์Šคํ„ฐ๋น™ํ•˜๋ฉด ๋œ๋‹ค.
    doReturn("Dexter").when(spy).get(0);
    assertThat(spy.get(0)).isEqualTo("Dexter");

    // 3. ์‹ค์ œ ๊ฐ์ฒด์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜์ง€๋งŒ, ๋‹น์—ฐํžˆ ์‹ค์ œ ๊ฐ์ฒด์— ์ ์šฉ๋œ ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.
    // ๊ทธ๋ž˜์„œ nameList.get()์„ ํ˜ธ์ถœํ•ด๋„ ์Šคํ„ฐ๋น™๋œ ๊ฐ’์ด ๋‚˜์˜ค์ง€์•Š์Œ.
    assertThatThrownBy(() -> nameList.get(0))
            .isInstanceOf(IndexOutOfBoundsException.class);
}

 

 

# 10. Mock ๊ฐ์ฒด ์ƒ์„ฑ ์ „๋žต์„ค์ •  (๊ฑฐ์˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ)

mock ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋”ฐ๋กœ ์Šคํ„ฐ๋น™์„ ํ•ด์ฃผ์ง€ ์•Š์œผ๋ฉด, ๊ธฐ๋ณธํƒ€์ž…(int,boolean)์„ ์ œ์™ธํ•˜๊ณ ๋Š” ์ „๋ถ€ null์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๋งŒ๋“ค์–ด์ง„๋‹ค. โžก mock ๊ฐ์ฒด์˜ ์ƒ์„ฑ์ „๋žต์„ ์ง€์ •ํ•ด์ฃผ์–ด์„œ ์ž๋™์œผ๋กœ ๋ฐ˜ํ™˜๊ฐ’์„ ๋งŒ๋“ค๋„๋ก ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

* ๋‹ค๋งŒ ์ด๋Š” ์˜ค๋ž˜๋œ ๋ ˆ๊ฑฐ์‹œ ์‹œ์Šคํ…œ์„ ํ…Œ์ŠคํŠธํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ๋ฉด, ์ด๋Ÿฐ์‹์œผ๋กœ ์‚ฌ์šฉํ•  ์ผ์ด ์—†๋‹ค. ๊ทธ๋ƒฅ ์•Œ์•„๋งŒ ๋‘์ž
@Test
void default_returnMock() throws Exception {
    // 1. ๊ทธ๋ƒฅ mock ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๋ฉด, ๊ธฐ๋ณธ ๋ฐ˜ํ™˜๊ฐ’์€ ์ „๋ถ€ null์ด๋‹ค.
    final Product mock = mock(Product.class);
    assertThat(mock.getName()).isNull();
    assertThatThrownBy(() -> mock.getName().length())
            .isInstanceOf(NullPointerException.class);

    // 2. RETURNS_SMART_NULL์„ ์ƒ์„ฑ์ „๋žต์œผ๋กœ ์ง€์ •ํ•œ ๊ฒฝ์šฐ.
    // NPE ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
    final Product mockWithSmartNulls = mock(Product.class, RETURNS_SMART_NULLS);
    assertThat(mockWithSmartNulls.getName()).isNotNull();
    assertThat(mockWithSmartNulls.getName().length()).isEqualTo(0);
}

 

 

# 11. ArgumentCaptor

verify(Object).method(...) ์‚ฌ์šฉ ์‹œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ง์ ‘ ์ง€์ •ํ•˜์ง€๋งŒ, ArgumentCaptor๋ฅผ ์ด์šฉํ•˜๋ฉด ์œ ์—ฐํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

@Test
void capture() throws Exception{
    // stubbing
    final List<String> mockedList = mock(List.class);
    when(mockedList.get(1)).thenReturn("A");
    when(mockedList.get(2)).thenReturn("B");
    when(mockedList.get(3)).thenReturn("C");

    // 1. Integer ๊ฐ’์„ ๋‹ค๋ฃจ๋Š” ArgumentCaptor ์ƒ์„ฑ
    ArgumentCaptor<Integer> integerArgumentCaptor = ArgumentCaptor.forClass(Integer.class);

    assertThat(mockedList.get(1)).isEqualTo("A");
    assertThat(mockedList.get(3)).isEqualTo("C");
    assertThat(mockedList.get(2)).isEqualTo("B");
    
    // 2. ์ž…๋ ฅ๋œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋‹ค์‹œ Captor(ํš๋“)ํ•ด์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
    final List<Integer> allValues = integerArgumentCaptor.getAllValues();
    assertThat(allValues).isEqualTo(Arrays.asList(1, 3, 2));


    // 3. ArgumentCaptor๋ฅผ ์ด์šฉํ•˜๋ฉด times(3) ์ฒ˜๋Ÿผ ๋™์ ์œผ๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
    verify(mockedList, times(3)).get(integerArgumentCaptor.capture());
    // verify(mockedList).get(1);
    // verify(mockedList).get(2);
    // verify(mockedList).get(3);

}

 

 

# 12. Resetting Mocks (๊ฑฐ์˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ)

์Šคํ„ฐ๋น™ ๋œ ๊ฐ’์„ mock ๊ฐ์ฒด์˜ ์ดˆ๊ธฐ์ƒํƒœ(null)๋กœ ๋˜๋Œ๋ ค๋ฒ„๋ฆด ์ˆ˜ ์žˆ๋‹ค. ๋‹ค๋งŒ ํ…Œ์ŠคํŠธ๋ฅผ ์ด๋”ฐ๊ตฌ๋กœ ํ•˜๋Š”๊ฑด ์ข‹์ง€์•Š์€ ๋ฐฉ๋ฒ•์ด๋‹ค.

@Test
void reset_mock() throws Exception{
    final Product mock = mock(Product.class);

    when(mock.getName()).thenReturn("Dexter");
    assertThat(mock.getName()).isEqualTo("Dexter");

    reset(mock);
    assertThat(mock.getName()).isNull();
}

 

 

# 13. Behavior Driven Development (BDD)

ํ–‰์œ„ ์ฃผ๋„ ์„ค๊ณ„ BDD๋ผ๊ณ  ๋ถˆ๋ฆฌ๋ฉฐ  given->when->then ๊ตฌ์กฐ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

Mocktio์˜ ๊ธฐ๋ณธ ๋ฉ”์„œ๋“œ๋“ค, when().thenReturn()๋“ฑ์€ ์ด๊ฒŒ ์Šคํ„ฐ๋น™์„ ํ•˜๋Š”๊ฑด์ง€, ๊ฒ€์ฆ์„ ํ•˜๋Š”๊ฑด์ง€ ์˜๋ฏธ๊ฐ€ ๋ช…ํ™•ํ•˜์ง€ ์•Š๋‹ค.

โžก ๋‚˜๋„ ์ฒ˜์Œ ๊ณต๋ถ€ํ• ๋•Œ๋Š” when()์ด ์Šคํ„ฐ๋น™์ด ์•„๋‹ˆ๋ผ ๊ฒ€์ฆํ•˜๋Š” ์ฝ”๋“œ๋กœ ์ฐฉ๊ฐํ–ˆ์—ˆ๋‹ค. ๋‚˜๋งŒ ๊ทธ๋Ÿฐ๊ฒŒ ์•„๋‹ˆ์—ˆ๊ตฌ๋‚˜ ใ…Žใ…Ž;

 

๊ทธ๋ž˜์„œ mockito.BDDMockito๋ผ๋Š” ์ถ”๊ฐ€ ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด BDD๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์ข‹์€ ํ™•์‹คํ•œ ๋ฉ”์„œ๋“œ๋“ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  • given(product.getName()).willReturn("Dexter"); => when๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ
  • then(product).should(times(1)).getName(); => verify์™€ ๊ฐ™์€ ๊ธฐ๋Šฅ
import org.junit.jupiter.api.*;
import org.mockito.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.*; // ์ถ”๊ฐ€ ํŒจํ‚ค์ง€ ์‚ฌ์šฉ

public class EX2_Mockito_BDD {

    @Mock Product product;

    @BeforeEach
    void init(){
        MockitoAnnotations.initMocks(this);
    }
    
    @Test
    void BDD_test() throws Exception{
        //given(...).willReturn()์œผ๋กœ ์ข€ ๋” ๋ช…ํ™•ํ•œ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•œ๋‹ค.
        given(product.getName()).willReturn("Dexter");

        //when
        final String name = product.getName();

        //then
        assertThat(name).isEqualTo("Dexter");

        then(product).should(times(1)).getName(); // verify๋ž‘ ๊ฐ™์€ ๊ธฐ๋Šฅ!
    }
}

 

 

# 14. @Captor, @Spy

์œ„์—์„œ @Mock ์ฒ˜๋Ÿผ ์–ด๋…ธํ…Œ์ด์…˜์„ ์ด์šฉํ•ด์„œ ArugmentCaptor, Spy๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

@Captor
ArgumentCaptor<Integer> integerArgumentCaptor;

@Test
void capture() throws Exception {
    MockitoAnnotations.initMocks(this);

    final List<String> mockedList = mock(List.class);
    when(mockedList.get(1)).thenReturn("A");
    when(mockedList.get(2)).thenReturn("B");
    when(mockedList.get(3)).thenReturn("C");

    assertThat(mockedList.get(1)).isEqualTo("A");
    assertThat(mockedList.get(3)).isEqualTo("C");
    assertThat(mockedList.get(2)).isEqualTo("B");

    verify(mockedList, times(3)).get(integerArgumentCaptor.capture());

    final List<Integer> allValues = integerArgumentCaptor.getAllValues();
    assertThat(allValues).isEqualTo(Arrays.asList(1, 3, 2));
}
@Spy
Product productSpy = new Product(1L, "Dexter", 1000);

@Spy
Product productSpyWithNoArgCon; // new Product();

@Test
void spy_annotation() throws Exception {
    MockitoAnnotations.initMocks(this);

    assertThat(productSpy.getName()).isEqualTo("Dexter");
    assertThat(productSpyWithNoArgCon.getName()).isNull();

    when(productSpy.getName()).thenReturn("James");
    when(productSpyWithNoArgCon.getName()).thenReturn("James");

    assertThat(productSpy.getName()).isEqualTo("James");
    assertThat(productSpyWithNoArgCon.getName()).isEqualTo("James");
}

 

# 14-1 @InjectMocks

@InjectMocks๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋ฉด, ํ˜„์žฌ ์ƒ์„ฑ๋˜์–ด์žˆ๋Š” Mock, Spy๋“ค์„ ์ฃผ์ž…ํ•ด์„œ ๋งŒ๋“ค์–ด์ค€๋‹ค.

์ผ์ข…์˜ Mock์„ ์œ„ํ•œ @Autowired๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด๋œ๋‹ค. ๋‹ค๋งŒ @Mock์ด ์—†๋‹ค๊ณ  ํ•ด์„œ ์‹ค์ œ๊ฐ์ฒด๊ฐ€ ์ฃผ์ž…๋˜์ง€๋Š” ์•Š๋Š”๋‹ค.

class Item{...}

class Order{
    private Item item;

    public Order(Item item) {
        this.item = item;
    }
}
public class EX3_Mockito_InjectMocks {

    @Mock
    Item item;

    @InjectMocks // mock(Item.class)๊ฐ€ ์ฃผ์ž…๋œ๋‹ค.
    Order order;

    @Test
    void injectMocks_Annotation() throws Exception{
        MockitoAnnotations.initMocks(this);

        when(item.isSameName("Book")).thenReturn(true);

        assertThat(order.itemCheck("Book")).isEqualTo("ํ•ด๋‹น ์•„์ดํ…œ์ด ์ฃผ๋ฌธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
        assertThat(order.itemCheck("Movie")).isEqualTo("์ฃผ๋ฌธ๋œ ์•„์ดํ…œ์ด ์•„๋‹™๋‹ˆ๋‹ค.");
    }
}

 

์ฐธ๊ณ ๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด Mockito.Annotations.openMocks(this) ๋ฅผ ์ด์šฉํ•ด์„œ @Mock์„ ์ฃผ์ž…๋ฐ›๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๋‹ค.

* ์ฐธ๊ณ ๋กœ ์›๋ž˜ initMocks()์˜€๋Š”๋ฐ ์ด๋ฆ„์ด openMocks๋กœ ๋ฐ”๋€Œ์—ˆ๋‹ค. ์ข€ ๋” ๋ช…ํ™•ํ•œ ์˜๋ฏธ๋กœ ๋ฐ”๋€๋“ฏ.

public class EX3_Mockito_InjectMocks {

    @Mock
    Item item;

    @Test
    void non_injectMocks_Annotation() throws Exception{
        MockitoAnnotations.openMocks(this); // Mock ๊ฐ์ฒด ์ปจํ…Œ์ด๋„ˆ ์‚ฌ์šฉ

        final Order order = new Order(item); // item์€ Mock ๊ฐ์ฒด ์ปจํ…Œ์ด๋„ˆ์—์„œ ๊บผ๋‚ด์™€์„œ ๋“ฑ๋ก

        when(item.isSameName("Book")).thenReturn(true);

        assertThat(order.itemCheck("Book")).isEqualTo("ํ•ด๋‹น ์•„์ดํ…œ์ด ์ฃผ๋ฌธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
        assertThat(order.itemCheck("Movie")).isEqualTo("์ฃผ๋ฌธ๋œ ์•„์ดํ…œ์ด ์•„๋‹™๋‹ˆ๋‹ค.");

    }
}

 

 

# 15. Ignore Stubbing

๋ณดํ†ต verifyNoMoreInteractions(mock);๋ฅผ ์“ธ ๋•Œ ์ข…์ข… ์‚ฌ์šฉํ•œ๋‹ค.

verifyNoMoreInteractions(mock); ๋Š” ํ•ด๋‹น Mock์— ๋ชจ๋“  ์Šคํ„ฐ๋น™์„ ์‚ฌ์šฉํ–ˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค.

@Test
void ignore_stubbing() throws Exception{
    final List<String> mock = mock(List.class);

    when(mock.get(0)).thenReturn("Hello");
    final String s = mock.get(0);

    ignoreStubs(mock);
    
    // verify(mock).get(0); ํ•˜์ง€ ์•Š์•„๋„ ํ†ต๊ณผ!. ignore๊ฐ€ ๋‚จ์€ ์Šคํ„ฐ๋น™์„ ๋‹ค ์ œ๊ฑฐํ•ด์คŒ.
    verifyNoMoreInteractions(mock);
}

 

 

# 16. Mocking details

Mock ๊ฐ์ฒด์˜ ์„ธ๋ถ€์‚ฌํ•ญ๋“ค์„ ํ…Œ์ŠคํŠธํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค. ๊ฑฐ์˜ ์‚ฌ์šฉํ• ์ผ์€ ์—†๊ธดํ•˜์ง€๋งŒ ์˜ˆ์ œ๋ฅผ ํ•œ๋ฒˆ ์‚ดํŽด๋ณด์ž.

@Mock
Product mockedProduct;

@Test
void mocking_details() throws Exception {
    MockitoAnnotations.openMocks(this); // mock ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.
    
    // ์›ํ•˜๋Š” mock์— ๋Œ€ํ•œ MockingDetails ๊ฐ์ฒด ์ƒ์„ฑ
    final MockingDetails mockingDetails = mockingDetails(mockedProduct);

    // 1. ํ•ด๋‹น Mock์ด mock, spy์ธ์ง€ ํ™•์ธ ๊ฐ€๋Šฅํ•˜๋‹ค.
    final boolean isMock = mockingDetails.isMock();
    assertThat(isMock).isTrue();
    final boolean isSpy = mockingDetails.isSpy();
    assertThat(isSpy).isFalse();

    // 2. Mocking ๊ฐ์ฒด์˜ ์ด๋ฆ„(mockedProduct)์™€ ์›๋ณธ๊ฐ์ฒด์˜ ํƒ€์ž… ๊ฒ€์ฆ๋„ ๊ฐ€๋Šฅ.
    final MockName mockName = mockingDetails.getMockCreationSettings().getMockName();
    assertThat(mockName.toString()).isEqualTo("mockedProduct");
    final Class<?> typeToMock = mockingDetails.getMockCreationSettings().getTypeToMock();
    assertThat(typeToMock).isSameAs(Product.class);

    // 3. ํ•ด๋‹น Mock์ด ๊ฐ€์ง„ ๋ฉ”์„œ๋“œ๊ฐ€ ๋‚ด๊ฐ€ ์ƒ๊ฐํ•˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ๋งž๋Š”์ง€ ๋น„๊ต๊ฐ€๋Šฅ.
    mockedProduct.setPrice(10000);
    final Method setPrice = typeToMock.getMethod("setPrice", int.class);
    mockingDetails.getInvocations().forEach(
            invocation -> assertThat(invocation.getMethod()).isEqualTo(setPrice)
    );

    // 4. ์Šคํ„ฐ๋น™๋œ ๊ฐ’๋“ค์˜ ์ •๋ณด๋„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Œ.
    when(mockedProduct.getName()).thenReturn("Dexter");
    final Method getName = typeToMock.getMethod("getName");
    mockingDetails.getStubbings().forEach(stubbing -> {
                final Method method = stubbing.getInvocation().getMethod();
                assertThat(method).isEqualTo(getName);
            }
    );
}

 

 

#17 Custom Verify Fail-Message

verify ์‹คํŒจ ์‹œ ์›ํ•˜๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ์ปค์Šคํ…€ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@Test
void custom_verify_failure_message() throws Exception{
    verify(mock, description("This will print on failure")).someMethod();
    
    final List<String> mockedList = mock(List.class);
    // times()๋“ฑ๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹์œผ๋กœ ์“ฐ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
    verify(mockedList, times(2).description("ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋Š” ๋‘๋ฒˆ ํ˜ธ์ถœ๋˜์–ด์•ผ ํ•œ๋‹ค.")).get(0);
}

 

 

----------

์ด์ •๋„๋ฉด ์ถฉ๋ถ„ํ•œ ๊ฒƒ ๊ฐ™๋‹ค.

๋” ๊ถ๊ธˆํ•œ ๋‚ด์šฉ์ด ์žˆ๋‹ค๋ฉด ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์ž.

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

JiwonDev

JiwonDev

ํ™œ๋™ํ•˜๊ธฐ