IT박스

Mockito에서 미완성 스터 빙 감지

itboxs 2020. 7. 8. 08:07
반응형

Mockito에서 미완성 스터 빙 감지


테스트를 실행하는 동안 다음과 같은 예외가 발생합니다. 조롱을 위해 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;
    }
}

조롱 안에 조롱하고 있습니다. 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 can't read your source code, so in order to figure out what you are asking it to do, it relies a lot on static state. When you call a method on a mock object, Mockito records the details of the call in an internal list of invocations. The when method reads the last of these invocations off the list and records this invocation in the OngoingStubbing object it returns.

The line

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

causes the following interactions with Mockito:

  • Mock method mainModel.getList() is called,
  • Static method when is called,
  • Method thenReturn is called on the OngoingStubbing object returned by the when method.

The thenReturn method can then instruct the mock it received via the OngoingStubbing method to handle any suitable call to the getList method to return someModelList.

In fact, as Mockito can't see your code, you can also write your mocking as follows:

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

This style is somewhat less clear to read, especially since in this case the null has to be casted, but it generates the same sequence of interactions with Mockito and will achieve the same result as the line above.

However, the line

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

causes the following interactions with Mockito:

  1. Mock method mainModel.getList() is called,
  2. Static method when is called,
  3. A new mock of SomeModel is created (inside getSomeList()),
  4. Mock method model.getName() is called,

At this point Mockito gets confused. It thought you were mocking mainModel.getList(), but now you're telling it you want to mock the model.getName() method. To Mockito, it looks like you're doing the following:

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

This looks silly to Mockito as it can't be sure what you're doing with mainModel.getList().

Note that we did not get to the thenReturn method call, as the JVM needs to evaluate the parameters to this method before it can call the method. In this case, this means calling the getSomeList() method.

Generally it is a bad design decision to rely on static state, as Mockito does, because it can lead to cases where the Principle of Least Astonishment is violated. However, Mockito's design does make for clear and expressive mocking, even if it leads to astonishment sometimes.

Finally, recent versions of Mockito add an extra line to the error message above. This extra line indicates you may be in the same situation as this question:

3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed

참고URL : https://stackoverflow.com/questions/26318569/unfinished-stubbing-detected-in-mockito

반응형