【问题标题】:Unit-testing with mockito (partial mocking)使用 mockito 进行单元测试(部分模拟)
【发布时间】:2011-05-13 20:44:17
【问题描述】:

我对 Mockito 有疑问。

有没有可能做这样的事情:

ClassX x = mock(ClassX.class)
when(x.methodB()).thenReturn("toto");
String result = x.methodA();

我正在使用 Mockito 1.7。

我看到有一个“间谍”系统,但他们说不建议在我们测试的项目上使用它(为什么?)...

我还是尝试了那个间谍功能,但我得到了一个奇怪的行为。

检查我想做什么:

真实代码:

String methodA(String arg) {
    return this.methodB(arg);
}

String methodB(String arg) {
    return "toto";
}

测试代码:

@Test
public void testTest() {
    final ClassX x = spy( new ClassX() );
    final String argument = "arg";
    doReturn("good").when(helper).methodB(argument);
    assertTrue(  x.methodB(argument).equals("good") );
    assertTrue(  x.methodA(argument).equals("good") );
}  

正如他们所说,我避免了可能对间谍造成问题的 when thenReturn 语法(但无论如何它也不起作用)

奇怪的是: assertTrue(x.methodB(argument).equals("good")); 没问题

只有第二个 assertTrue(x.methodA(argument).equals("good")); 不行

实际上 helper.methodA(argument) 返回 "toto" -> 真实结果而不是模拟结果

在这种情况下,不可能告诉 mockito 返回“好”???好像测试类调用methodB的时候没问题,但是如果spy的方法调用methodB就不行了……

我不知道该怎么办...对同一个类的 2 个方法进行单元测试并让测试彼此独立以使著名的模拟测试框架无法实现是不是很奇怪?这个基本功能?这不就是我们所说的真正的单元测试吗?不明白为什么他们说要避免对被测对象使用 spy 方法...

谢谢

【问题讨论】:

  • 刚刚在 Mockito 1.9.5 上尝试过,都返回了 "good"。所以我猜这种行为已经消失了。

标签: java unit-testing mocking mockito partial-mocks


【解决方案1】:

更新: 我在下面写了这些东西,然后过了一会儿发现了 .thenCallRealMethod() ,它可以让你有效地执行部分存根。 Mockito 作者建议您使用重构将依赖项分离到不同的类中;但它们确实提供了部分存根的方法。我添加了一个测试方法来演示这种方法,并保留我原来的 cmets。

原件: 我真的很喜欢 Mockito,但这是 EasyMock 胜出的地方。我有两个不涉及 Mockito 的解决方案。第一个是在您的测试实例上覆盖 methodB。另一种是用 EasyMock 进行部分模拟:

import org.junit.Test;
import static org.junit.Assert.*;
import static org.easymock.EasyMock.*;

public class PartialMockTest {

    class ClassX {
        String methodA(String arg) {return methodB(arg);}
        String methodB(String arg) {return "toto";}
    }

    @Test
    public void MockitoOnClassX(){
        ClassX classx = mock(ClassX.class);
        when(classx.methodB("hiyas")).thenReturn("tomtom");
        when(classx.methodA(anyString())).thenCallRealMethod();
        String response = classx.methodA("hiyas");
        assertEquals("tomtom",response);
    }


    @Test
    public void OverrideOnClassX() {
        ClassX classx = new ClassX(){@Override String methodB(String arg){return "tomtom";}};
        String response = classx.methodA("hiyas");
        assertEquals("tomtom",response);
    }

    @Test
    public void PartialMockOnClassX() throws NoSuchMethodException {
        ClassX classx = createMockBuilder(ClassX.class).addMockedMethod("methodB").createMock();
        expect(classx.methodA("hiyas")).andReturn("tomtom");
        replay(classx);
        String response = classx.methodA("hiyas");
        assertEquals("tomtom",response);
    }

}

【讨论】:

    【解决方案2】:

    间谍与被监视的对象是不同的对象。 spy 只委托给被监视的对象。所以当被监听的对象从methodA调用methodB时,它会调用它自己,而不是spy。

    【讨论】:

    • 谢谢 :) 但是你有解决方案来做我想做的事吗?
    • 我想我可以使用一个匿名的真实类并覆盖 MethodB 但 mockito 没有给出适合该解决方案的方法?
    • 而是将methodB 放在您提供的另一个对象上,作为具有methodA 的对象的依赖项,例如作为构造函数参数。这样你就可以模拟 methodB 对象。如果您给出对象和方法的正确名称,我可以为您建议更好的名称。
    • 谢谢。所以似乎没有解决方案使用 spy 并将 2 方法放在同一个类中......伤心
    • 应该将 methodB 移出只是为了模拟和测试,即使 (1) methodAmethodB 完全属于同一类,并且 (2) @987654327 @是methodA使用的一段通用代码?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-22
    • 1970-01-01
    • 2020-01-03
    相关资源
    最近更新 更多