嵌套模拟中的方法上的Mockito doNothing

时间:2019-07-15 20:49:43

标签: java unit-testing mockito

假设我有3个类,ClassA包含一个ClassB,ClassB包含一个ClassC。 我正在尝试在ClassA中测试一个方法,该方法需要调用ClassB来获取ClassC的实例并在ClassC中执行VOID方法(我知道这是错误的,因为ClassA不应该知道ClassC,代码有异味,这是而不是我的代码,而只是尝试对其进行测试)。 但是,当我尝试使用Mockito.doNothing跳过该方法调用时,出现以下错误:

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
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!
 3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed

代码如下:

ClassA:

    public class ClassA {
        private ClassB classB;

        public ClassA(ClassB classB) {
            this.classB = classB;
        }

        public void methodToTest() {
            classB.getClassC().someVoidMethod("123");
        }
    }

ClassB:

    public class ClassB {
        private ClassC classC;

        public ClassB(ClassC classC) {
            this.classC = classC;
        }

        public ClassC getClassC() {
            return classC;
        }

    }

ClassC:

    public class ClassC {
        public void someVoidMethod(String arg) {
            System.out.println(arg);
        }
    }

测试类

    @RunWith(MockitoJUnitRunner.class)
    public class ClassATest {

        @InjectMocks
        private ClassA classA;

        @Mock(answer = Answers.RETURNS_DEEP_STUBS)
        private ClassB classB;

        @Mock
        private ClassC classC;

        @Test
        public void test() {
            Mockito.doNothing().when(classB.getClassC()).someVoidMethod("123");
        }    
    }

再次,此代码不是我的,因此我无法修改其使用依赖项的方式。我只是在尝试测试。

快速说明: Mockito.when(...)。thenReturn(...)可以正常工作,但这不是我的情况,因为我要模拟的方法是无效的。

2 个答案:

答案 0 :(得分:4)

我认为这可行。我不确定为什么您不能使用classB.getClassC()而不是直接引用classC

@RunWith(MockitoJUnitRunner.class)
public class ClassATest {

  @InjectMocks
  private ClassA classA;

  @Mock(answer = Answers.RETURNS_DEEP_STUBS)
  private ClassB classB;

  @Mock
  private ClassC classC;

  @Before
  public void init() {
    doReturn(classC).when(classB).getClassC();
    doNothing().when(classC).someVoidMethod("123");
  }

  @Test
  public void test() {
    classA.methodToTest();
  }
}

答案 1 :(得分:2)

您的模拟语法安排不正确。

Mockito.doNothing().when(classB.getClassC()).someVoidMethod("123");

在此语句的各个部分添加空格时,很明显。

Mockito      response                    method                  method
Mockito      .doNothing()     .when(classB.getClassC())    .someVoidMethod("123");

当您将Method传递给when时,它会期望thenReturn 当您将OBJECT传递给when时,您可以从中链接一个void方法。

Mockito.when(classB.getClassC()).thenReturn(classC);
Mockito.doNothing().when(classC).someVoidMethod("123");

之所以无法像您认为的那样工作,是因为classB.getClassC()在通过when()时不像吸气剂那样工作。

您实际上并没有将对对象的引用传递给Mockito,而是使用thenReturn将Mockito为您存根的方法,它抱怨说缺少该方法是因为您没有这样做有一个。

tl:dr;

  

在模拟存根代码中,请勿将模拟对象方法视为实际方法。