【问题标题】:Mockito doNothing on a method inside a nested mockMockito doNothing 在嵌套模拟中的方法上
【发布时间】:2019-07-15 20:49:43
【问题描述】:

假设我有 3 个类,ClassA 包含一个 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

代码如下:

A 类:

    public class ClassA {
        private ClassB classB;

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

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

B 类:

    public class ClassB {
        private ClassC classC;

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

        public ClassC getClassC() {
            return classC;
        }

    }

C类:

    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(...) 工作正常,但这不是我的情况,因为我试图模拟的方法是无效的。

【问题讨论】:

  • 在你的 C 模拟上存根 someVoidMethod 来做你想做的任何事情。然后在 B 的模拟上存根 getClassC,以返回 C 的模拟。
  • 不太确定这是否是您所说的,但添加了 Mockito.when(classB.getClassC()).thenReturn(classC);在调用 Mockito.doNorthing() 之前,但仍然是相同的异常
  • 不,这不是我说要做的。好的,以后有时间我会回复的。

标签: java unit-testing mockito


【解决方案1】:

我认为这行得通。我不知道你为什么不能使用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();
  }
}

【讨论】:

  • 设置存根时,请记住您不是在使用真正的方法调用,而是在构建 mockito 语句时使用 存根方法调用classB.getClassC() 是在 when() 中使用时要存根的方法调用,而不是实际的 classC 对象引用。一开始有点奇怪,因为这似乎与 OOP 的概念背道而驰。
【解决方案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() 时不像getter 那样工作。

您实际上并没有将对该对象的引用传递给 Mockito,而是 Mockito 将为您存根的方法thenReturn,它抱怨缺少该方法,因为您没有.

tl:dr;

不要将模拟对象方法视为模拟存根代码中的实际方法。

【讨论】:

  • 对不起,我自己在括号里搞混了。 when 可以采用有返回值的方法,也可以采用没有返回值的方法。 classB.getClassC() 返回 ClassC,因此它需要一个“thenReturn”链。编译器在那里失败了。
  • 两个语句中的哪一个有相同的异常?
  • 等等,我想我错了,似乎可以工作,让我确认一下
  • @LuisMiguel 太棒了!我试图澄清一下解释。基本上,模拟对象方法,尤其是 getter 和 setter,不像 Mockito 存根代码中的 getter 和 setter。
猜你喜欢
  • 2018-04-28
  • 2017-06-03
  • 1970-01-01
  • 2014-09-21
  • 2013-11-17
  • 2021-02-19
  • 1970-01-01
  • 2023-03-05
  • 1970-01-01
相关资源
最近更新 更多