IT이야기

모키토를 사용할 때 조롱하는 것과 스파이하는 것의 차이점은 무엇입니까?

cyworld 2022. 6. 21. 23:02
반응형

모키토를 사용할 때 조롱하는 것과 스파이하는 것의 차이점은 무엇입니까?

모키토 스파이를 사용할 경우 어떤 활용 사례가 있을까요?

모든 스파이 유스케이스는 callRealMethod를 사용하여 모의로 처리할 수 있을 것 같습니다.

내가 알 수 있는 한 가지 차이점은 대부분의 메서드 호출을 실제 호출로 만들고 싶을 경우 모의 호출과 스파이 호출을 사용하는 코드 행이 절약된다는 것입니다.그게 다야? 아니면 내가 더 큰 그림을 놓치고 있는 거야?

스파이와 모의의 차이점

Mockito는 실제 인스턴스가 아닌 Class of a Type에서 모크를 만듭니다.모크는 클래스의 베어본 셸 인스턴스를 만들 뿐이며, 이 인스턴스와 상호작용을 추적하기 위해 완전히 계측됩니다.반면 스파이는 기존 인스턴스를 랩합니다.일반 인스턴스와 동일한 방식으로 작동합니다. 유일한 차이점은 이 인스턴스와 모든 상호 작용을 추적하도록 계측된다는 것입니다.

다음 예에서는 ArrayList 클래스의 모크를 만듭니다.

@Test
public void whenCreateMock_thenCreated() {
    List mockedList = Mockito.mock(ArrayList.class);

    mockedList.add("one");
    Mockito.verify(mockedList).add("one");

    assertEquals(0, mockedList.size());
}

보시는 바와 같이 요소를 조롱 목록에 추가해도 실제로는 아무것도 추가되지 않으며 다른 부작용 없이 메서드를 호출할 수 있습니다.반면 스파이는 다른 동작을 합니다.즉, 실제로는 add 메서드의 실제 구현을 호출하여 기본 목록에 요소를 추가합니다.

@Test
public void whenCreateSpy_thenCreate() {
    List spyList = Mockito.spy(new ArrayList());
    spyList.add("one");
    Mockito.verify(spyList).add("one");

    assertEquals(1, spyList.size());
}

여기서는 size() 메서드를 호출하면 크기가 1이 되기 때문에 객체의 실제 내부 메서드가 호출되었다고 말할 수 있지만, 이 size() 메서드는 조롱당하지 않습니다!그럼 1은 어디서 온 걸까요?내부 real size() 메서드는 size()가 조롱(또는 stubbed)되지 않기 때문에 실제 객체에 엔트리가 추가되었다고 할 수 있습니다.

출처 : http://www.baeldung.com/mockito-spy + 셀프노트.

정답은 설명서에 있습니다.

실제 부분 모크(1.8.0 이후)

마지막으로 메일링 리스트에 대한 내부 논의와 논의를 거듭한 끝에 모키토에 부분적인 모의 지원이 추가되었다.이전에는 코드 냄새로 부분 모크를 고려했습니다.그러나 부분 모크에 대한 정당한 사용 사례를 발견했습니다.

릴리스 1.8 이전에는 spy()가 실제 부분 모크를 생성하지 않아 일부 사용자에게 혼란을 주고 있었습니다.스파이 방법에 대한 자세한 내용은 여기를 참조하거나 javadoc for spy(Object) 메서드를 참조하십시오.

callRealMethod() was spy() 호환성을 하기 위해

그지않 、 ,이말맞맞 。 스파이의 모든 수법은 뭉개지지 않는 한 진짜야.모조품의 모든 수법은 단점이 있다.callRealMethod()반, 음, 음, 음, 음, 음, 음, 음, 음, in, in, 음, 음, 음, 음, 음, 음, 음, 음, 음, 음, 음, 음, 음, 음, 음, 음, ,callRealMethod()doXxx().when()when().thenXxx()

8개의 메서드를 가진 객체가 있고 7개의 실제 메서드와 stub1개의 메서드를 호출하는 테스트가 있는 경우 두 가지 옵션이 있습니다.

  1. 모크를 사용하면 7 callRealMethod와 stub1개의 메서드를 호출하여 설정해야 합니다.
  2. 「」의 spy 가지 세팅해야 합니다.

관한 공식 문서doCallRealMethod이치노

부분 모크에 대한 자세한 내용은 javadoc spy(개체)도 참조하십시오.Mockito.spy()는 부분 모크를 만드는 권장 방법입니다.그 이유는 spy() 메서드에 전달된 오브젝트의 구성을 담당하기 때문에 올바르게 구성된 오브젝트에 대해 실제 메서드가 호출된다는 것을 보증하기 때문입니다.

스파이는 레거시 코드에 대한 장치 테스트를 생성할 때 유용합니다.

https://www.surasint.com/mockito-with-spy/ 에서 실행 가능한 예를 작성했습니다.그 중 일부를 여기에 복사합니다.

다음과 같은 코드가 있는 경우:

public void transfer(  DepositMoneyService depositMoneyService, WithdrawMoneyService withdrawMoneyService, 
             double amount, String fromAccount, String toAccount){
    withdrawMoneyService.withdraw(fromAccount,amount);
    depositMoneyService.deposit(toAccount,amount);
}

당신은 예금금 서비스나 인출금 서비스를 흉내낼 수 있기 때문에 스파이가 필요 없을지도 모른다.

그러나 일부 레거시 코드에서는 다음과 같은 종속성이 코드 안에 있습니다.

    public void transfer(String fromAccount, String toAccount, double amount){

        this.depositeMoneyService = new DepositMoneyService();
        this.withdrawMoneyService = new WithdrawMoneyService();

        withdrawMoneyService.withdraw(fromAccount,amount);
        depositeMoneyService.deposit(toAccount,amount);
    }

네, 첫 번째 코드로 변경할 수 있지만 API는 변경됩니다.이 방법이 여러 곳에서 사용되고 있다면 모두 변경해야 합니다.

또는 다음과 같이 의존관계를 추출할 수 있습니다.

    public void transfer(String fromAccount, String toAccount, double amount){
        this.depositeMoneyService = proxyDepositMoneyServiceCreator();
        this.withdrawMoneyService = proxyWithdrawMoneyServiceCreator();

        withdrawMoneyService.withdraw(fromAccount,amount);
        depositeMoneyService.deposit(toAccount,amount);
    }
    DepositMoneyService proxyDepositMoneyServiceCreator() {
        return new DepositMoneyService();
    }

    WithdrawMoneyService proxyWithdrawMoneyServiceCreator() {
        return new WithdrawMoneyService();
    }

그런 다음 다음과 같이 spy를 사용하여 종속성을 주입할 수 있습니다.

DepositMoneyService mockDepositMoneyService = mock(DepositMoneyService.class);
        WithdrawMoneyService mockWithdrawMoneyService = mock(WithdrawMoneyService.class);

    TransferMoneyService target = spy(new TransferMoneyService());

    doReturn(mockDepositMoneyService)
            .when(target).proxyDepositMoneyServiceCreator();

    doReturn(mockWithdrawMoneyService)
            .when(target).proxyWithdrawMoneyServiceCreator();

자세한 내용은 위의 링크를 참조하십시오.

[더블 타입 테스트]

Mock »Spy

Mock는 베어 이중 객체입니다.은 비어 및 합니다.

Spy는 복제된 이중 객체입니다. 개체는 실제 개체를 기반으로 복제되지만 이를 조롱할 수 있습니다.

class A {
    String foo1() {
        foo2();
        return "RealString_1";
    }

    String foo2() {
        return "RealString_2";
    }

    void foo3() { foo4(); }

    void foo4() { }
}
@Test
public void testMockA() {
    //given
    A mockA = Mockito.mock(A.class);
    Mockito.when(mockA.foo1()).thenReturn("MockedString");

    //when
    String result1 = mockA.foo1();
    String result2 = mockA.foo2();

    //then
    assertEquals("MockedString", result1);
    assertEquals(null, result2);

    //Case 2
    //when
    mockA.foo3();

    //then
    verify(mockA).foo3();
    verify(mockA, never()).foo4();
}

@Test
public void testSpyA() {
    //given
    A spyA = Mockito.spy(new A());

    Mockito.when(spyA.foo1()).thenReturn("MockedString");

    //when
    String result1 = spyA.foo1();
    String result2 = spyA.foo2();

    //then
    assertEquals("MockedString", result1);
    assertEquals("RealString_2", result2);

    //Case 2
    //when
    spyA.foo3();

    //then
    verify(spyA).foo3();
    verify(spyA).foo4();
}

언급URL : https://stackoverflow.com/questions/15052984/what-is-the-difference-between-mocking-and-spying-when-using-mockito

반응형