简体   繁体   English

检查是否未调用方法

[英]Check that a method is not invoked

I want to check that a method is not run and tried to do it with an Expectation setting times = 0; 我想检查一个方法是不是运行并尝试使用Expectation设置times = 0; , however I don't get the expected behaviour. 但是我没有得到预期的行为。

For example, the following test passes, although the Session#stop method is called, and the expectation has a times = 0; 例如,虽然调用了Session#stop方法,但是期望的times = 0; ,所以通过了以下测试times = 0; condition: 条件:

public static class Session {
    public void stop() {}
}

public static class Whatever {
    Session s = new Session();
    public synchronized void method() {
        s.stop();
    }
}

@Test
public void testWhatever () throws Exception {
    new Expectations(Session.class) {
        @Mocked Session s;
        { s.stop(); times = 0; } //Session#stop must not be called
    };
    final Whatever w = new Whatever();
    w.method(); // this method calls Session#stop => the test should fail...
                // ... but it passes
}

Note: If I replace the code with { s.stop(); times = 1; } 注意:如果我用{ s.stop(); times = 1; }替换代码 { s.stop(); times = 1; } { s.stop(); times = 1; } , the test passes too: I must be missing something obvious here... { s.stop(); times = 1; } ,测试通过太:我必须缺少的东西在这里很明显...

The reason of the unexpected mocking behavior is that you inadvertently used partial mocking on an strictly mocked type. 出现意外模拟行为的原因是您无意中对严格模拟的类型使用了部分模拟。 In this case, recording an expectation with times = <n> means that the first n matching invocations will be mocked, and after that any additional invocations will execute the original "unmocked" method. 在这种情况下,使用times = <n>记录期望意味着将模拟前n匹配的调用,之后任何其他调用将执行原始的“unmocked”方法。 With regular mocking instead, you would get the expected behavior (ie, an UnexpectedInvocation getting thrown after n invocations). 使用常规模拟,您将获得预期的行为(即,在n调用后抛出UnexpectedInvocation )。

The proper way to write the test is: 编写测试的正确方法是:

public static class Session { public void stop() {} }
public static class Whatever {
    Session s = new Session();
    public synchronized void method() { s.stop(); }
}

@Test
public void testWhatever ()
{
    new Expectations() {
        @Mocked Session s;
        { s.stop(); times = 0; }
    };

    final Whatever w = new Whatever();
    w.method();
}

Alternatively, it can also be written with a verification block instead, which is usually better for situations like these: 或者,它也可以用验证块编写,这通常适用于以下情况:

@Test
public void testWhatever (@Mocked final Session s)
{
    final Whatever w = new Whatever();
    w.method();

    new Verifications() {{ s.stop(); times = 0; }};
}

Related to this I had trouble with JMockit, times = 0 and the @Tested annotation. 与此相关的我遇到了JMockit,times = 0和@Tested注释的问题。

With the @Tested annotation you still have a 'real' class, so when registering an Expectation or a Verification (even with times = 0) on this real class, JMockit tries to execute the method. 使用@Tested注释,你仍然有一个'真正的'类,所以当在这个真正的类上注册Expectation或Verification(甚至是times = 0)时,JMockit会尝试执行该方法。 Solution is to partially mock the class in the Expectations: 解决方案是在Expectations中部分模拟类:

@Tested
Session s;

new Expectations(Session.class) {{ 
   s.stop(); times = 0; } //Session#stop must not be called
};

This is the only way I found to use times=0 on methods from @Tested classes. 这是我发现在@Tested类的方法中使用times = 0的唯一方法。

I found a workaround with the MockUp class - the test below fails as expected - I would still like to understand why the original approach was not working . 我找到了MockUp类的解决方法 - 下面的测试按预期失败 - 我仍然想了解为什么原始方法不起作用

@Test
public void testWhatever () throws Exception {
    new MockUp<Session>() {
        @Mock
        public void stop() {
            fail("stop should not have been called");
        }
    };
    final Whatever w = new Whatever();
    w.method();
}

Try maxTimes instead, you also can reference stop() in a static way: 尝试使用maxTimes,您也​​可以以静态方式引用stop():

@Test
public void test(@Mocked Session mockSession){

  final Whatever w = new Whatever();
  w.method();

  new Verifications(){
    {
       Session.stop();
       maxTimes = 0;
    }
  };
}

From memory, something like 从记忆中,像是

verify( s  , times(0) ).stop();

will work. 将工作。 Trouble is, the Session in Whatever isn't your @Mock 'ed one, but another object, so insert a 麻烦的是, Session中的Whatever不是你的@Mock的ed,而是另一个对象,所以插入一个

w.s = s;

just before w.method() . 就在w.method()之前。

Cheers, 干杯,

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM