JMockit:覆盖@Mocked类

时间:2015-05-29 21:10:40

标签: java unit-testing mocking jmockit

我有一个内部StreamGobbler类,里面有7个方法。 我正在寻找一种默认模拟所有方法的快捷方法,但是覆盖一个名为getOutput()的方法(例如Partial Mocking)。

(为清晰起见,未显示完整代码)

public class StreamGobbler extends Thread
{
    public String getOutput() 
    public void run()
}

我想要的是将@Mocked注释与MockUp结合使用来部分模拟getOutput方法,但保留所有"默认"在所有其他方法上模拟代码。在部分模拟的文档中,它指出如果你使用MockUp,所有非@Mock方法都保留它们的正常功能。有时这很好,但在这种情况下,这不是我想要的。

这与问题JMockit: @Mocke and MockUp combination in the same test类似,但我只是在查看方法计数时无法逃脱。

如果我有这样的测试设置:

@Test
public void execute(@Mocked StreamGobbler sg)
{
    new MockUp<StreamGobbler>()
    {
        String type = null;

        @Mock
        void $init(String type)
        {
            this.type = type;
        }

        @Mock
        String getOutput()
        {
            if ("OUTPUT".equals(type))
            {
                return "test output";
            }
            else 
            {
                return "";
            }
        }
     }
 }

我收到此错误java.lang.IllegalArgumentException: Class already mocked

如果我尝试在MockUp中添加@Override注释,它没有帮助(而Eclipse抱怨它)

处理此问题的最佳方法是什么?在此测试方法之外使用静态类?

使用JMockit 1.17和TestNG

总之,我如何模拟StreamGobbler中的每个方法(与@Mocked一样),但是部分覆盖一个方法(没有在MockUp中自己手动完成?)

2 个答案:

答案 0 :(得分:1)

满足给定约束条件的完整示例代码:

public static class StreamGobbler extends Thread {
    public StreamGobbler(String type) {}
    public String getOutput() { return null; }
    @Override public void run() {}
}

public static class TestedClass {
    public String doSomething() throws InterruptedException {
        StreamGobbler sg1 = new StreamGobbler("OUTPUT");
        sg1.start();

        StreamGobbler sg2 = new StreamGobbler("ERROR");
        sg2.start();

        sg1.join(5000);
        sg2.join(5000);

        String output1 = sg1.getOutput();
        String output2 = sg2.getOutput();
        return output1 + '|' + output2;
    }
}

@Test
public void useStreamGobbler(@Mocked StreamGobbler sg) throws Exception {
    new Expectations() {{
        new StreamGobbler("OUTPUT").getOutput(); result = "test output";
        new StreamGobbler("ERROR").getOutput(); result = "";
    }};

    String output = new TestedClass().doSomething();

    assertEquals("test output|", output);
}

答案 1 :(得分:0)

首先,由于您正在创建MockUp类的匿名子类,因此使用@Override注释肯定是不合适的。您提供的那些方法不属于MockUp类,而是属于您提供的通用。

稍后在运行时期间(通过一些令人印象深刻的过程(基于我读到的here,我假设AOP))你在这个类中创建的实例将使用你提供的方法签名而不是它自己的

在更详尽地阅读Mock课程上的API以及从JMockit's Getting Started页面获取一些信息之后,我认为您的问题完全在于另一个领域。如果您有其他测试方法,他们将干扰此方法。

您得到的错误是:“已经为类型 StreamGobbler 声明了MockUp实例,并且在此测试方法的参数中调用了 Mocked 注释试图用相同的泛型声明另一个MockUp实例,你违反了JMockit的规定。“ 我会检查你是否在测试方法之外创建一个实际的StreamGobbler MockUp,如果是这样的话(1)如果你想使用它,不要在方法中重新声明另一个MockUp实例,而是继续使用Mocked注释或者(2)如果你不想使用它并且你想重新声明一个包装StreamGobbler的MockUp的新实例,不要在测试方法的参数中使用Mocked注释,而是保持MockUp实例化。