Mockito Spy 测试

10
我正在使用Mockito为代码编写测试。然而,我卡在了以下场景上 - 类A有两个方法,method1()和method2()。我尝试使用ArgumentCaptor捕获发送到method2()的值。但是,由于我正在使用@Spy,所以我无法使用Matchers。
我该如何测试method1()?
class A{
    B b;
    method1(arg1, arg2){
       //some logic
       method2(arg1, arg2, ....argN);
    }

   method2(arg1, arg2,....argN){
       //some logic
       b.method3(arg1, arg2...);
   }
}

如何验证method2接收相同的参数值? 以下是我编写的测试类:
Class TestA{

@Mock
B b;

@Spy
@InjectMocks   //required else b is null
A a = new A();

@Test
public void testMethod1(){

 a.method1(arg1, arg2);

  //How to verify method2 receives same argument values (arg1, arg2)????
  //verify(a, times(1)).method2(.......);   
}

}


我根据你和David的讨论添加了一个编码示例作为答案。 - Brad
3个回答

13

我被这个帖子和@David留下的评论所吸引,因此我决定为像我一样的人编写一个工作示例。

/*
 * class to test
 */
public class A {

    public void methodA(String str) {
        this.methodB(str);
    }

    protected void methodB(String str) {
        // some implementation
    }
}

我们希望断言传递给methodB()的值是我们期望的。研究ArgumentCaptor后,我发现了等效的Captor注释

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.verify;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class MultipleMethodCallTest {

    @Spy
    A a = new A();

    @Captor ArgumentCaptor<String> captor;

    @Test
    public void captureSecondMethodCallArgument() throws Exception {

        // EXPECTED

        String greeting = "hello world";

        // PERFORM TEST

        a.methodA(greeting);

        // ASSERT

        verify(a).methodB(captor.capture());

        assertEquals(greeting, captor.getValue());
    }
}

这个示例是使用以下版本进行测试的:

  • mockito-all-1.8.5.jar
  • junit-4.8.2.jar

请参考@Dawood ibn Kareem的下面的答案。https://dev59.com/ymPVa4cB1Zd3GeqP1wm6#10292649 这是正确的答案。 - Midhun Vijayakumar

3

您无法直接验证,必须通过B的method3调用来进行验证。如果您传递给method2的参数对method3没有影响,那么这些参数可能是没有意义的?!


抱歉,我已经编辑了示例代码以反映传递给method3的args参数。是的,我可以验证method 3的调用。我在想,我是否正确编写了测试?因为我没有看到Spy和InjectMocks同时使用的示例。是否有更好的方法来编写测试用例? - aces.

2
你可以在间谍中使用匹配器,这样就可以正常工作。我不知道你为什么认为不能这样做。
我拿到了你的源代码,并编辑它使其编译通过。然后我添加了一个调用MockitoAnnotations.initMocks - 你需要这个来创建间谍和模拟对象,并注入模拟对象(除非你使用MockitoJUnitRunner,它会为你执行initMocks)。我把对method2的调用的verify放回去了。这个方法很好用。
所以,与Omnaest的回答相反,你不需要使用B的method3来验证它。我怀疑你唯一的问题是忘记了initMocks
祝你好运,并随时发布更多帮助请求。

是的,你说得对,CGLIB确实扩展了类,因此它可以覆盖method2,因此甚至可以捕获内部调用。因此,基本上Mockito可以在这种情况下做到这一点。尽管如此,我从未在实际应用程序中看到过这种情况,因为大多数情况下内部方法都声明为私有的。因此,您被迫至少使用包或受保护的方式声明内部方法。我不知道这是否是一个好方法。但是问题似乎指向了mockito的能力,所以肯定是可以的。 - Omnaest
@DavidWallace:我正在使用RunWith(MockitoJUnitRunner.class)注释,当我尝试'verify(a, times(1)).method2(.......)'时,异常是“_verify()应该与模拟对象一起使用_”。而且我确实有一个问题:“这是测试这种情况的最佳方法吗?”我是Mockito的新手,仍在通过实验学习。 - aces.
好的,我刚刚再次尝试了一下,使用MockitoJUnitRunner而不是直接调用initMocks。对我来说,测试仍然通过;没有异常。我使用的是Mockito 1.9.0-RC1,但我不认为在RC1和1.9.0正式发布之间在这个领域有任何变化。你使用的是哪个版本的Mockito,这样我就可以继续尝试重现你的问题了? - Dawood ibn Kareem
@DavidWallace - 是的,我正在使用最新的Mockito版本1.9.0。我没有之前得到的确切错误消息。不管怎样,现在它已经可以工作了。谢谢。 - aces.
1
@aces 你应该接受这个作为正确答案。当我看到这个被当前接受的答案排名比这个高时,我差点没往下读。 - Brad
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接