Mockito에서 미완성 스터 빙 감지


151

테스트를 실행하는 동안 다음과 같은 예외가 발생합니다. 조롱을 위해 Mockito를 사용하고 있습니다. Mockito 라이브러리가 언급 한 힌트는 도움이되지 않습니다.

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
    -> at com.a.b.DomainTestFactory.myTest(DomainTestFactory.java:355)

    E.g. thenReturn() may be missing.
    Examples of correct stubbing:
        when(mock.isOk()).thenReturn(true);
        when(mock.isOk()).thenThrow(exception);
        doThrow(exception).when(mock).someVoidMethod();
    Hints:
     1. missing thenReturn()
     2. you are trying to stub a final method, you naughty developer!

        at a.b.DomainTestFactory.myTest(DomainTestFactory.java:276)
        ..........

테스트 코드에서 DomainTestFactory. 다음 테스트를 실행하면 예외가 나타납니다.

@Test
public myTest(){
    MyMainModel mainModel =  Mockito.mock(MyMainModel.class);
    Mockito.when(mainModel.getList()).thenReturn(getSomeList()); // Line 355
}

private List<SomeModel> getSomeList() {
    SomeModel model = Mockito.mock(SomeModel.class);
    Mockito.when(model.getName()).thenReturn("SomeName"); // Line 276
    Mockito.when(model.getAddress()).thenReturn("Address");
    return Arrays.asList(model);
}

public class SomeModel extends SomeInputModel{
    protected String address;
    protected List<SomeClass> properties;

    public SomeModel() {
        this.Properties = new java.util.ArrayList<SomeClass>(); 
    }

    public String getAddress() {
        return this.address;
    }

}

public class SomeInputModel{

    public NetworkInputModel() {
        this.Properties = new java.util.ArrayList<SomeClass>(); 
    }

    protected String Name;
    protected List<SomeClass> properties;

    public String getName() {
        return this.Name;
    }

    public void setName(String value) {
        this.Name = value;
    }
}

안녕하세요 Mureinik, 나는 줄 번호로 게시물을 업데이트했습니다
Royal Rose

답변:


371

조롱 안에 조롱하고 있습니다. 에 getSomeList()대한 조롱을 마치기 전에을 조롱하는 중입니다 MyMainModel. Mockito는 당신이 이것을 할 때 그것을 좋아하지 않습니다.

바꾸다

@Test
public myTest(){
    MyMainModel mainModel =  Mockito.mock(MyMainModel.class);
    Mockito.when(mainModel.getList()).thenReturn(getSomeList()); --> Line 355
}

@Test
public myTest(){
    MyMainModel mainModel =  Mockito.mock(MyMainModel.class);
    List<SomeModel> someModelList = getSomeList();
    Mockito.when(mainModel.getList()).thenReturn(someModelList);
}

이것이 왜 문제를 일으키는 지 이해하려면 Mockito의 작동 방식에 대해 약간 알아야하고 Java에서 평가되는 표현식 및 명령문의 순서를 알아야합니다.

Mockito는 소스 코드를 읽을 수 없으므로 요청한 내용을 파악하려면 정적 상태에 크게 의존합니다. 모의 객체에서 메소드를 호출하면 Mockito는 호출의 세부 사항을 내부 호출 목록에 기록합니다. 이 when메소드는 마지막 호출을 목록에서 읽고이 호출을 OngoingStubbing리턴 하는 오브젝트 에 기록 합니다.

라인

Mockito.when(mainModel.getList()).thenReturn(someModelList);

Mockito와 다음과 같은 상호 작용을 일으 킵니다.

  • 모의 메서드 mainModel.getList()를 호출
  • 정적 메소드 when가 호출됩니다.
  • 메소드 thenReturnOngoingStubbing리턴 한 오브젝트 에서 메소드 가 호출됩니다 when.

thenReturn방법은 다음을 통해 수신 된 모의 지시 할 OngoingStubbing받는 임의의 적절한 통화 처리하는 방법을 getList반환하는 방법 someModelList.

실제로 Mockito는 코드를 볼 수 없으므로 다음과 같이 조롱을 작성할 수 있습니다.

mainModel.getList();
Mockito.when((List<SomeModel>)null).thenReturn(someModelList);

이 스타일은 읽기가 다소 null어렵 습니다. 특히이 경우에는 캐스팅해야하기 때문에 Mockito와 동일한 시퀀스의 상호 작용을 생성하며 위의 라인과 동일한 결과를 얻을 수 있습니다.

그러나 라인

Mockito.when(mainModel.getList()).thenReturn(getSomeList());

Mockito와 다음과 같은 상호 작용을 일으 킵니다.

  1. 모의 메서드 mainModel.getList()를 호출
  2. 정적 메소드 when가 호출됩니다.
  3. mockSomeModel생성 (내부 getSomeList())
  4. 모의 메서드 model.getName()를 호출

이 시점에서 Mockito는 혼란스러워합니다. 그것은 당신이 조롱 mainModel.getList()하고 있다고 생각 했지만, 지금 당신은 당신이 model.getName()방법 을 조롱하고 싶다고 말하고 있습니다 . Mockito에게는 다음을 수행하는 것처럼 보입니다.

when(mainModel.getList());
// ...
when(model.getName()).thenReturn(...);

Mockito당신이하고있는 일을 확신 할 수 없으므로 어리석게 보입니다 mainModel.getList().

thenReturnJVM이 메소드를 호출하기 전에이 메소드에 대한 매개 변수를 평가해야 하므로 메소드 호출에 도달하지 않았습니다 . 이 경우 이는 getSomeList()메소드 호출을 의미합니다 .

일반적으로 Mockito와 마찬가지로 정적 상태에 의존하는 것은 좋지 않은 설계 결정입니다. 이는 최소 놀랍게도의 원칙을 위반하는 사례로 이어질 수 있기 때문입니다. 그러나 Mockito의 디자인은 때로는 놀랍게도 명확하고 표현적인 조롱을합니다.

마지막으로, Mockito의 최신 버전은 위의 오류 메시지에 추가 줄을 추가합니다. 이 추가 행은이 질문과 같은 상황에있을 수 있음을 나타냅니다.

3 : 완료되면 'thenReturn'명령 전에 다른 모의 동작을 스텁합니다.


이 사실에 대한 설명이 있습니까? 솔루션이 작동합니다. 그리고 왜 'in-place'모의 제작이 작동하지 않는지 이해하지 못합니다. mock을 만들고 다른 mock을 참조하여 만든 mock을 전달하면 작동합니다.
Capacytron

1
훌륭한 답변, 사랑해! 혼자서 이것을 찾는
데는 오랜 시간이 걸렸을

4
좋은 답변 루크! 간단한 단어로 매우 자세한 설명. 감사합니다.
Tomasz Kalkosiński

1
대박. 재미있는 방법은 직접 메소드 호출을 수행하고 천천히 디버그하면 작동합니다. CGLIB $ BOUND의 속성은 true 값을 갖지만 약간의 시간이 걸립니다. 직접 메소드 호출을 사용하고 훈련 전에 멈출 때 (... 때) 값이 먼저 거짓임을 알게되고 나중에 참이됩니다. 거짓이고 훈련이 시작되면이 예외가 발생합니다.
Michael Hegner

당신은 내 하루를했다! 이것은 많은 시간을 낭비하게 만드는 일종의 오류입니다! 나는 그것이 처음에 kotlin과 관련이 있다고 생각했다
Bronx

1
org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
E.g. thenReturn() may be missing.

void 메소드를 조롱하려면 아래를 시도하십시오.

//Kotlin Syntax

 Mockito.`when`(voidMethodCall())
           .then {
                Unit //Do Nothing
            }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.