Jmockit:如何验证在特定实例上调用的方法

时间:2015-04-17 08:27:51

标签: java unit-testing jmockit

我在Java 1.7上使用JMockit 1.15。

我想验证一些经过测试的代码首先创建一个特定类的新实例( ExampleClass ),然后在该实例上调用一个方法。 我尝试了许多方法,使用验证,期望,@Mocked,@ Injectable以多种方式,但我无法成功。

以下是一个例子。

ExampleClass 是一个类;我要模仿它,我想验证它是如何使用的。

public class ExampleClass {

    final double id = Math.random();

    public ExampleClass() {
    }

    public void doSomething() {
        System.out.println("I did something - " + id);
    }

}

ExampleClassUser 包含我想要测试的逻辑。

请注意,wrongUsage()构建了ExampleClass的两个实例,但总是在第一个上调用doSomething()。

public class ExampleClassUser {

    public void rightUsage() {
        final ExampleClass exampleClass1 = new ExampleClass();
        exampleClass1.doSomething();

        final ExampleClass exampleClass2 = new ExampleClass();
        exampleClass2.doSomething();
    }

    public void wrongUsage() {
        final ExampleClass exampleClass1 = new ExampleClass();
        exampleClass1.doSomething();

        final ExampleClass exampleClass2 = new ExampleClass();
        exampleClass1.doSomething();
    }

}

ExampleClassUserTest 是我想要构建的测试。 它应检查每个方法是否调用rightUsage()或wrongUsage()

  1. 创建一个ExampleClass的新实例
  2. 在该实例上调用doSomething
  3. 创建ExampleClass的另一个实例
  4. 在第二个实例上调用doSomething
  5. 应用于rightUsage()时测试应该成功,并且当应用于wrongUsage()时测试失败。

    当然,我的测试无法做到这一点,因为它只是检查是否正在创建新实例并且执行了两个方法调用,但是**没有检查方法调用执行的实例“

    import mockit.FullVerificationsInOrder;
    import mockit.Mocked;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    
    
    @RunWith(mockit.integration.junit4.JMockit.class)
    public class ExampleClassUserTest {
    
        @Test
        public void testUsage(final @Mocked ExampleClass exampleClass) {
    
            //new ExampleClassUser().rightUsage();
            new ExampleClassUser().wrongUsage();
    
            new FullVerificationsInOrder() {{
                new ExampleClass();
                exampleClass.doSomething();
    
                new ExampleClass();
                exampleClass.doSomething();
            }};
    
        }
    
    }
    

2 个答案:

答案 0 :(得分:1)

使用JMockit 1.17或更新版本,以下版本的测试将起作用(即,它将按预期失败):

@Test
public void testUsage(@Mocked ExampleClass exampleClass)
{
    new ExampleClassUser().wrongUsage();

    new FullVerificationsInOrder() {{
        ExampleClass e1 = new ExampleClass(); // matches first new instance
        e1.doSomething(); // matches only on instances equivalent to "e1"

        // Same as before, now for the second instance.
        ExampleClass e2 = new ExampleClass();
        e2.doSomething(); // fails with a "missing invocation"
    }};
}

答案 1 :(得分:0)

测试实例化对象的方法有点困难,因为在您无法访问新创建的实例的方法之外。对此的解决方案是使用Factory创建ExampleClass实例,工厂将其作为依赖项传递给ExampleClassUser。现在您可以控制,因为您可以模拟工厂以返回所需的任何对象(模拟,自定义单元测试对象等),并且由于您可以访问这些对象,因此可以对它们进行断言。

另一种方法,如果你不强烈需要确保调用了对象/方法,那就是不要断言调用正确的对象/方法,而是断言这些调用的效果。这将有利于将测试与方法实现分离。只有当doSomething()具有无需访问对象时可以检测到的副作用时,此方法才可行,并且可能涉及复杂的设置。

例如,如果doSomething()返回素数并且每次调用它,则返回下一个素数(第一个调用将返回2,第二个3,依此类推),测试方法将添加两个数字,返回它们(是的,我知道愚蠢的例子),您可以检测是否在两个不同的对象上调用doSomething(),因为它们的总和是4.如果在同一个对象上调用doSomething(),则返回结果是5。