JMockit:覆盖@Mocked class

JMockit: Overriding @Mocked class

我有一个内部 StreamGobbler class,其中有 7 个方法。 我正在寻找一种默认情况下模拟所有方法的快速方法,但覆盖一个名为 getOutput() 的方法(例如部分模拟)。

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

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

我想要的是结合使用 @Mocked 注释和 MockUp 来部分模拟 getOutput 方法,但保留所有其他方法的所有 "default" 模拟代码。在有关部分模拟的文档中,指出如果您使用 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 抱怨它)

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

使用 JMockit 1.17 和 TestNG

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

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

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

阅读 Mock class more thoroughly as well as getting some information from JMockit's Getting Started 页面上的 API 后,我认为您的问题完全出在不同的领域。如果你有其他的测试方法,他们会干扰这个方法。

您遇到的错误是:"There is already an instance of MockUp declared for the type StreamGobbler, and by calling the Mocked annotation in this test method's parameters and attempting to declare another instance of MockUp with the same generic, you are violating a JMockit stipulation." 我会检查您是否在测试方法之外创建了 StreamGobbler 的实际 MockUp,如果是这样 (1) 如果您想使用它,请不要在该方法中重新声明 MockUp 的另一个实例,但继续使用 Mocked 注释或者 (2) 如果您不想使用它并且想重新声明一个新的 MockUp 实例包装 StreamGobbler,请不要在测试方法的参数中使用 Mocked 注释,但保留 MockUp 实例化。

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

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);
}