JMockit:如何使用新的模拟覆盖已经被模拟的方法?

4

我想我可能在JMockit中发现了一个bug,但我想确认一下是不是真的有bug或者是否有我没有注意到的东西。

我有一个非常简单的类:

public class Dummy {
    public void foo() {System.out.println("O");}
}

现在我有以下测试,每个测试中我都尝试模拟方法“foo”多次(每个测试都略有不同):
测试#1
@Test
public void test1() {

    new MockUp<Dummy>() {

        @Mock
        public void foo(Invocation inv) {

            System.out.println("A");
            inv.proceed();
        }
    }

    new MockUp<Dummy>() {

        @Mock
        public void foo(Invocation inv) {

            System.out.println("B");
            inv.proceed();
        }
    }

    new Dummy().foo();
}

测试 #2

@Test
public void test2() {

    mock("A");
    mock("B");
    new Dummy().foo();
}

private void mock(final String s) {

    new MockUp<Dummy>() {

        @Mock
        public void foo(Invocation inv) {

            System.out.println(s);
            inv.proceed();
        }
    }
}

唯一的区别在于将模拟代码提取到不同的方法中。但结果是不同的...
测试#1输出:
B
A
B
O

这很奇怪,因为我根本不希望 A 出现。但无论如何,以下是第二个测试的输出:

B
A
A
A
...ad infinitum

第二个测试将因为StackOverflowError而失败。

这是一个bug还是我漏掉了什么?

更新(解决方案)

正如@Rogério提到的,这种行为是不可接受的。
那么如何覆盖模拟?像这样:

private MockUp<Dummy> mock;

@Test
public void test3() {

        mockCorrectly("A");
        mockCorrectly("B");
        new Dummy().foo();
}


private void mockCorrectly(final String s) {

    if (mock != null) {
        mock.tearDown();
    }

    mock = new MockUp<Dummy> {

        @Mock
        public void foo(Invocation inv) {

            System.out.println(s);
            inv.proceed();
        }
    }
}

关于输出:

B
O

非常好 :)


你在使用 @Injectable 时是否成功过使用顶层 MockUp 类?无论我尝试了什么,我都无法让顶层 MockUp 类自动装配到我的测试类中。 - Eric B.
1个回答

4

这里发生了什么并不清楚,显然在运行时会发生一些"链接模拟"。

真正的问题是两个测试都在使用MockUp API进行无效操作:它们在同一个测试中两次模拟相同类别的方法。在同一个测试中,如果它们模拟不同的方法/构造函数,则可以为同一类别拥有两个不同的模拟。

结果的行为是未定义的,因为JMockit不支持同时对同一方法进行多次模拟。


谢谢。你知道如何模拟对象的方法并覆盖它吗?我发现这个功能很重要,因为我在“setUp”(@Before)中以某种方式模拟了类中的一个方法,但是在某些特定的测试中,我希望该方法有不同的行为。 - Eyal Roth
我想我找到了答案。我会编辑问题并附上解决方案。 - Eyal Roth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接