Mockito 스파이의 사용 사례는 무엇입니까?
callRealMethod를 사용하여 모든 스파이 유스 케이스를 모의로 처리 할 수있는 것 같습니다.
내가 볼 수있는 한 가지 차이점은 대부분의 메서드 호출을 실제로 원한다면 모의 대 스파이를 사용하기 위해 코드 줄을 절약합니다. 그것이 더 큰 그림입니까?
답변
답은 설명서에 있습니다 .
실제 부분 모형 (1.8.0부터)
마지막으로 메일 링리스트에 대한 많은 내부 토론과 토론 끝에 Mockito에 부분 모의 지원이 추가되었습니다. 이전에는 코드 냄새로 부분 모의를 고려했습니다. 그러나 부분 모의에 대한 합법적 인 사용 사례를 발견했습니다.
릴리스 1.8 이전 spy ()는 실제 부분 모의를 생성하지 않았으며 일부 사용자에게는 혼란 스러웠습니다. 스파이에 대한 자세한 내용은 here 또는 spy (Object) 메소드에 대한 javadoc을 참조하십시오 .
callRealMethod()
는 이후에 소개 spy()
되었지만 이전 버전과의 호환성을 보장하기 위해 spy ()가 남아 있습니다.
그렇지 않으면, 당신이 옳습니다 : 스파이의 모든 방법은 스텁되지 않는 한 실제입니다. 모의의 모든 메소드 callRealMethod()
는 호출 되지 않는 한 스텁됩니다 . 일반적으로 나는 전통적인 대신 관용구 callRealMethod()
를 사용하도록 강요하지 않기 때문에을 선호합니다.doXxx().when()
when().thenXxx()
답변
스파이와 모의 차이점
Mockito가 모의 객체를 만들 때 – 실제 인스턴스가 아닌 클래스의 클래스에서 모의 객체를 만듭니다. 이 모의는 단순히 클래스의 베어 셸 인스턴스를 생성하고 클래스와의 상호 작용을 추적하기 위해 완전히 계측되었습니다. 반면에 스파이는 기존 인스턴스를 감 쌉니다. 여전히 일반 인스턴스와 동일한 방식으로 작동합니다. 유일한 차이점은 인스턴스와의 모든 상호 작용을 추적하도록 인스트루먼트됩니다.
다음 예제에서 – 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은 어디에서 왔습니까? 내부 실제 size () 메서드는 size ()가 조롱 (또는 스터 빙)되지 않기 때문에 항목이 실제 객체에 추가되었다고 말할 수 있습니다.
출처 : http://www.baeldung.com/mockito-spy + 자기 메모.
답변
8 개의 메소드가있는 오브젝트가 있고 7 개의 실제 메소드를 호출하고 하나의 메소드를 스텁하려는 테스트가있는 경우 두 가지 옵션이 있습니다.
- 모의를 사용하면 7 callRealMethod를 호출하고 하나의 메소드를 스텁하여 설정해야합니다.
- 를 사용하면
spy
하나의 방법을 스텁하여 설정해야합니다
공식 문서 에 대한 doCallRealMethod
부분 모의 객체에 대한 스파이를 사용하는 것이 좋습니다.
부분 모의에 대한 자세한 내용은 javadoc spy (Object)를 참조하십시오. 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);
}
DepositMoneyService와 WithdrawMoneyService를 조롱 할 수 있기 때문에 스파이가 필요하지 않을 수 있습니다.
그러나 일부 레거시 코드에서 종속성은 다음과 같은 코드에 있습니다.
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();
}
그런 다음 스파이를 사용하여 다음과 같이 종속성을 주입 할 수 있습니다.
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
베어 더블 오브젝트입니다. 이 객체는 동일한 메소드 서명을 가지고 있지만 실현은 비어 있고 기본값-0과 null을 반환합니다.
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();
}