如何使用Mockito验证重载方法的调用次数?

如何使用Mockito验证重载方法的调用次数?

问题描述:

如何使用Mockito检查 bar(Alpha,Baz)是否为 bar(Xray,Baz)在没有实际调用后者的情况下,给定我的MCVE类 Foo

How do I check if bar(Alpha, Baz) called bar(Xray, Baz) using Mockito - without actually calling the later, given my MCVE class Foo:

public class Foo {
    public String bar(Xray xray, Baz baz) {
        return "Xray";
    }

    public String bar(Zulu zulu, Baz baz) {
        return "Zulu";
    }

    public String bar(Alpha alpha, Baz baz) {
        if(alpha.get() instanceof Xray) {
            return bar((Xray)alpha.get(), baz);
        } else if(alpha.get() instanceof Zulu) {
            return bar((Zulu)alpha.get(), baz);
        } else {
            return null;
        }
    }
}

目前,我大致有遵循Mockito增强的JUnit测试:

Currently, I have roughly the following Mockito-enhanced JUnit test:

@Test
public void testBar_callsBarWithXray() {
    Baz baz = new Baz(); //POJOs
    Alpha alpha = new Alpha();
    alpha.set(new Xray());

    Foo foo = new Foo();
    Foo stub = spy(foo); // Spying on Foo, as I want to call the real bar(Alpha, Baz)
    // Preventing bar(Xray, Baz) from being called by providing behavior/stub
    when(stub.bar(any(Xray.class), any(Baz.class))).thenReturn("ok");
    // Calling the real "parent" method
    stub.bar(alpha, baz);
    // Testing if bar(Xray, Baz) was called by bar(Alpha, Baz)
    verify(stub, times(1)).bar(any(Xray.class), any(Baz.class));
}

它失败了:

org.mockito.exceptions.verification.TooManyActualInvocations:
foo.bar(
    <any>,
    <any> ); 
Wanted 1 time:
-> at FooTest.testBar_callsBarWithXray(FooTest.java:14) 
But was 2 times. Undesired invocation:
-> at FooTest.testBar_callsBarWithXray(FooTest.java:12)

我想这是因为任何(Class.class)匹配任何东西,并且不进行类型检查......所以,从Mockito的角度来看,我真的在调用 bar()两次:在 Foo FooTest (第12行)。

I suppose it's because any(Class.class) matches anything, and doesn't do type checking... So, from Mockito's point of view, I'm really calling bar() twice: in Foo and in FooTest (on line 12).

我需要做些什么来使测试做我真正想要的事情:确保在我打电话时调用 bar(Xray,Baz) bar(Alpha,baz)(同时拦截对 bar(Xray,Baz)的调用)?

What do I have to do to make the test do what I actually want: ensure bar(Xray, Baz) was called when I call bar(Alpha, baz) (while at the same time intercepting the call to bar(Xray, Baz))?

使用 eq()匹配器(时(stub.bar(eq(Xray) .class),any(Baz.class))... )导致编译错误,无法解析方法'bar(Class< Xray>,Baz)' - 但是,我可能不应该那样使用它( eq(xray)可能更像它)...

Using the eq() Matcher (when(stub.bar(eq(Xray.class), any(Baz.class))...) causes a compilation error, Cannot resolve method 'bar(Class<Xray>, Baz)' - but then, I probably shouldn't use it that way anyway (eq(xray) would probably be more like it)...

此外,在相关说明中,如果我尝试重载 bar(Alpha,Baz) private ,我收到 FooTest 的编译错误,说明:

Also, on a related note, if I try to make the overloads of bar(Alpha, Baz) private, I get a compilation error for FooTest, stating:


错误:(10,12)java:bar(Xray,Baz)在Foo中拥有私人访问权限

Error:(10, 12) java: bar(Xray,Baz) has private access in Foo

有没有办法绕过那个使用PowerMockito?怎么样?
(显然,我只想计算对 bar(Xray,Baz)的调用 - 计算对栏的所有重载的所有调用( )是不可能的......)

Is there a way to get round that using PowerMockito? How? (Obviously, I only want to count the calls to bar(Xray, Baz) - counting all calls to all overloads of bar() is out of the question...)

只需使用 eq(xray)而不是测试第10行和第14行的任何(Xray.class)都可以解决问题 - 但我对 并不感兴趣(具体)Xray对象作为参数传递给 bar(),只要它是任何 Xray 对象...

Just using eq(xray) instead of any(Xray.class) on lines 10 and 14 of the test does the trick - but I'm not really interested in what (specific) Xray object is passed in as an argument to bar(), as long as it's any Xray object...

更新:我发布了单独的问题讨论中的PowerMockito和私有方法部分,并找出了如何使 public 方法;比照我的在下面发表评论

Update: I've posted a separate question for the "PowerMockito and private methods" part of the discussion, and figured out how to make this work for public methods; cf. my comment below.

你不需要这样做。



这让你疯狂的原因是你没有按照预期的方式使用Mockito。 可以以这种方式使用,但不应该这样。

You don't need to do this.

The reason this is driving you nuts is that you aren't using Mockito the way it is intended to be used. It can be used this way, but it should not be.

你不需要测试是否调用了正确的方法,你需要测试您班级的行为是否正确。这是什么意思?

You don't need to test that the right method was called, you need to test that the behavior of your class is correct. What does that mean?


  1. 你想要检查Xray已被退回。

String result = foo.bar(alpha, baz);
assertEquals("Xray", result);


  • 您想检查 Alpha.get 被叫了。如果有的话,这意味着 Alpha 应该是存根,而不是 Foo

  • You want to check that Alpha.get was called. If anything, this means that Alpha should be the stub, not Foo.

    Alpha alpha = spy(new Alpha());
    String result = foo.bar(alpha, baz);
    verify(alpha).get();
    


  • 底线是这样的:你有你的受测系统,在这种情况下 Foo 。该课程应该是真正的课程您的模拟和存根应该是与 Foo 交互的其他对象;验证交互做正确的事情

    The bottom line is this: You have your System Under Test, in this case Foo. That class should be a real class. Your mocks and stubs should be the other objects that interact with Foo; verify that the interactions do the correct things.

    换句话说,你不应该测试如何 Foo 有效,您应该测试 Foo 做它应该做的事情;结果是正确的。

    In other words, you shouldn't be testing how Foo works, you should be testing that Foo does what it's supposed to do; that the results are correct.