2017-12-14 3 views
0

Mockito의 스파이에서 스터 빙 방법에 "딥 스텁"을 사용할 수있는 방법을 찾을 수 없었습니다. 내가 뭘 찾고 있어요 것은이 같은 것입니다 :mockito의 스파이에 대한 Answers.RETURNS_DEEP_STUBS와 같습니다.

@Spy private Person person = //retrieve person 

    @Test 
    public void testStubbed() { 
     doReturn("Neil").when(person).getName().getFirstName(); 
     assertEquals("Neil", person.getName().getFirstName()); 
    } 

위의 코드는 문제없이 컴파일하지만 테스트를 실행에, 그것을 말하는 실패 반환 형식 (이 경우 이름 클래스) 할 수없는 그 getName()에 의해 돌려 주어집니다.

일반적으로 조롱 할 때 각각의 조롱 된 개체에 대해
@Mock(answer = Answers.RETURNS_DEEP_STUBS)을 사용해야합니다. 그러나 스파이는 이와 같은 것을 가지지 않습니다.

누구도 스파이를 사용하여 깊은 스터 빙 된 조롱을 성공적으로 마쳤습니까?

I 받고있어 오류가 아래와 같이 표시됩니다, 내가 오는 사람을위한 솔루션을 게시하고 싶습니다 나는 아직도이 할 수있는 더 좋은 방법이 있는지 알고 싶습니다 동안

String cannot be returned by getName() 
getName() should return Name 

Due to the nature of the syntax above problem might occur because of: 
1. Multithreaded testing 
//I'm not doing multithreaded testing 
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies with doReturn|Throw() family of methods 
//As shown above, I'm already using the doReturn family of methods. 

답변

0

찾고.

아래의 해결책은 각 모범 수준의 새로운 모의 (또는 실제 개체/스파이)를 만들어야하므로 잘 작동합니다. 즉, 스텁을 만들기 위해 메서드 호출을 연결하는 대신 각 수준을 개별적으로 조롱합니다.

@Spy private Person person = //retrieve person 
@Mock private Name name; 

@Test 
public void testStubbed() { 
    doReturn(name).when(person).getName(); 
    doReturn("Neil").when(name).getName(); 
    assertEquals("Neil", person.getName().getFirstName()); 
} 
+0

'@Mock Name name'에서'= new Name()'을 삭제해야합니다. Mockito는 초기화시 그 값을 덮어 씁니다. –

+0

맞습니다. 업데이트되었습니다. 이 선언문을 작성할 때 변수 선언에 많은주의를 기울이지 않았습니다. –

0

당신은 doAnswer(RETURNS_DEEP_STUBS)를 사용하여 원하는 깊이 스텁에 좀 더 가까이 얻을 수 있습니다,하지만 당신은 임의의 깊이 방법은 부모 호출을 스텁 돌보는없이 호출을 무시할 수 없습니다. 나는 답을 할 때 수동 단일 레벨 심의 조롱을 계속 사용하거나 가능한 경우 조롱을 덜 사용합니다.


스파이의 기본 동작은 실제 방법은 일반적으로 (당신의 이름과 같은)는 실제 개체를 반환 호출이 아닌 Mockito 스파이에 위임하는 것입니다. 즉, 일반적으로 Mockito를 사용하여 이러한 객체의 동작을 변경할 수는 없습니다. 스파이는 실제로 스파이 활동을하는 객체와 동일한 클래스는 아니지만 모든 필드 값이 스파이에서 복사되는 생성 된 하위 클래스입니다. -on 값. (위임하는 스파이가 매우 unintutitive 행동, this에 대한 메소드 호출과 필드 값을 포함있을 것입니다 때문에 복사가 중요한 기능이다.)

Foo foo = new Foo(); 
foo.intValue = 42; 
foo.someObject= new SomeObject(); 

Foo fooSpy = Mockito.spy(foo); 
// Now fooSpy.intValue is 42, fooSpy.someObject refers to the exact same 
// SomeObject instance, and all of fooSpy's non-final methods are overridden to 
// delegate to Mockito's behavior. Importantly, SomeObject is not a spy, and 
// Mockito cannot override its behavior! 

그래서이 작동하지 않습니다

doReturn("Neil").when(person).getName().getFirstName(); 
// Mockito thinks this call ^^^^^^^^^ should return "Neil". 

을 그리고 어느 쪽이됩니다 적어도 가장 바람직에서

상황에서
doReturn("Neil").when(person.getName()).getFirstName(); 
// The object here ^^^^^^^^^^^^^^^^ won't be a mock, and even if Mockito 
// could automatically make it a mock, it's not clear whether that 
// should be the same spy instance every time or a new one every time. 

, 나는 순서대로 다음을 선택할 것 :

  1. 실제 이름 개체를 만들고 doReturn을 사용하여 설치하십시오. 결국 이름은 데이터 객체 (일명 값 객체) 인 것처럼 보입니다. 종속성, 솔리드 동작 및 모의이 어려운 상태 전환이 없음을 의미합니다. 당신은 조롱해서 아무것도 얻지 못할 수도 있습니다.

  2. 모의 이름을 생성하고 as you do in your answer을 설치하십시오. 이것은, Name가 외형보다 복잡한 경우, 또는 실제로 Name이 존재하지 않는 경우에 특히 유용합니다.

    doReturn("Neil").when(person.getName()).getFirstName(); 
    

    당신이 다음 재정의 할 수 있습니다

  3. 깊은 스텁을 반환 대한 getName 교체 ...

    doAnswer(RETURNS_DEEP_STUBS).when(person).getName(); 
    

    ... ... ... 심지어 임의의 깊이 값. 최종 편집으로

    doReturn("Gaelic").when(person.getName() 
               .getEtymology() 
               .getFirstNameEtymology()) 
        .getOrigin(); 
    

는 부분 모의 객체의 위험 중 하나는 그것이 정말 열심히 진짜이고 어느 것이 위조하는 행위 말할 수 있다는 것입니다; 이것은 당신이 테스트하고있는 행동이 모의 행동이 아니라 모의 행동 인 것을 보장하는 것을 어렵게 만들 수도 있습니다. 깊은 스터브의 또 다른 위험은 사용자가 정의에 따라 Law of Demeter을 위반할 수 있다는 것입니다. 이러한 종류의 기술을 테스트에서 자주 사용하는 경우, 테스트 할 시스템을 다시 설계하는 것이 좋습니다.

관련 문제