注意:问题末尾附有完整工作的代码片段
我有一个类的 JMockIt 测试 Service
有两个依赖项(代码片段中的 Factory
和 Consumer
)。该服务内部询问 Factory
类 X
的对象的依赖关系,然后将该对象传递给 Consumer
该方法的依赖关系:
public void interact(int i, E e) {
X v = f.create(i, e);
c.consume(v);
}
在我的测试中,我想练习 Service.interact()
方法并通过严格的期望假设消费者应收到满足特定属性的参数值。现在,由于类型 X
的参数是一个没有实现 equals() 的 POJO,我想使用它提供的 getter 方法来执行我的检查; X
看起来像这样(完整的代码片段在问题末尾):
public static class X {
private final int i;
public final E e;
// ... see below for full snippet
public int getI() { return i; }
public E getE() { return e; } // E is an enum
所以我所做的就是尝试检查消费者是否收到 X.getI() == 2
的值和X.getE() == E.B
我使用with(Delegate<X>)
来做到这一点和withArgThat(Matcher<X>)
在我的期望 block 中:
new StrictExpectations() {{
consumer.consume(withArgThat(new BaseMatcher() { // ...
// and
new StrictExpectations() {{
consumer.consume(with(new Delegate() { // ...
但是,这两项检查都失败了,因为当它们调用 X.getE()
时他们收到的东西不是枚举值 E.B
。单元测试的输出为:
----------------------------------------- RUNNING CHECKS ON: i=2, e=B Direct reference match. Reference through getter mismatch! Ordinal through getter reference: 0 Identity hashcode from getter reference: 1282788025 Identity hashcode of expected reference: 519569038 ----------------------------------------- RUNNING CHECKS ON: i=2, e=B Direct reference match. Reference through getter mismatch! Ordinal through getter reference: 0 Identity hashcode from getter reference: 1911728085 Identity hashcode of expected reference: 519569038
第一个问题是(这篇文章的标题):为什么 JMockIt 首先要干预这个 getter?据我所知,我没有要求它模拟类 X,因此对其 getter 方法的调用应该进入常规 X 字节码,但显然它没有;返回的枚举值的序数为零,这似乎是模拟的默认值。这是预期的行为,因为我错过/误解了某些东西,或者它可能是一个错误?
第二个问题是:假设 JMockIt 的行为有正当理由,我怎样才能实现我想要的并对只能通过 X 的 getter 方法获取的值执行这种检查?我如何修复此代码以告诉 JMockIt 只需离开类 X
独自一人。
这是将编译和运行的完整代码片段(也在 http://pastebin.com/YRL7Pdzv ),我的类路径中有 junit-4.12、hamcrest-core-1.3 和 jmockit-1.14,并使用 Oracle JDK 1.7.0_51。
package demonstrate; import mockit.Delegate; import mockit.Mocked; import mockit.NonStrictExpectations; import mockit.StrictExpectations; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.junit.Before; import org.junit.Test; public class SomeTest { @Mocked Factory factory; @Mocked Consumer consumer; @Before public void setUp() { new NonStrictExpectations() {{ factory.create(anyInt, (E) any); result = new Delegate() { @SuppressWarnings("unused") public X create(int i, E e) { return new X(i, e); } }; }}; } @Test public void testWithMatcher() { System.err.println("-----------------------------------------"); new StrictExpectations() {{ consumer.consume(withArgThat(new BaseMatcher() { final int i = 2; final E e = E.B; @Override public boolean matches(Object item) { return runChecks((X) item, i, e); } @Override public void describeTo(Description description) { description.appendText("\"i=" + i + ", e=" + e.name() + "\""); } })); }}; new Service(factory, consumer).interact(2, E.B); } @Test public void testWithDelegate() { System.err.println("-----------------------------------------"); new StrictExpectations() {{ consumer.consume(with(new Delegate() { @SuppressWarnings("unused") public boolean check(X x) { return runChecks(x, 2, E.B); } })); }}; new Service(factory, consumer).interact(2, E.B); } private static boolean runChecks(X actual, int i, E e) { System.err.println("RUNNING CHECKS ON: " + actual); if (actual.getI() != i) { System.err.println("Primitive int mismatch!"); return false; } if (actual.e == e) { System.err.println("Direct reference match."); } else { System.err.println("Reference mismatch!"); return false; } E otherE = actual.getE(); if (otherE != e) { System.err.println("Reference through getter mismatch!"); System.err.println("Ordinal through getter reference: " + otherE.ordinal()); System.err.println("Identity hashcode from getter reference: " + System.identityHashCode(otherE)); System.err.println("Identity hashcode of expected reference: " + System.identityHashCode(e)); return false; } return true; } public enum E { A, B } public static class X { private final int i; public final E e; public X(int i, E e) { this.i = i; this.e = e; } @Override public String toString() { return "i=" + i + ", e=" + e.name(); } public int getI() { return i; } public E getE() { return e; } } public static class Factory { public X create(int i, E e) { return new X(i, e); } } public static class Consumer { public void consume(X arg) { } } public static class Service { private final Factory f; private final Consumer c; public Service(Factory f, Consumer c) { super(); this.f = f; this.c = c; } public void interact(int i, E e) { X v = f.create(i, e); c.consume(v); } } }
最佳答案
我在 jmockit-users 列表中被告知这实际上是一个错误。
建议的解决方法是使用 @Mocked(cascading = false) Factory 工厂;
,它确实使事情正常工作。
关于java - 为什么 JMockIt 在这段代码中模拟 X 类的 getter X.getE() ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27731395/