gpt4 book ai didi

java - 使用 JMock 的类 类型参数的模拟方法

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:59:17 30 4
gpt4 key购买 nike

背景:

这是一个 JMock+JUnit 特定问题(这是我必须使用的两种技术)。是的,我想做的事情可以用 PowerMock 来完成,但这是一个边缘案例,不需要更换工具。不,抱歉,我问这个问题不是为了辩论静态方法的哲学有效性:)

除此之外,我真的要感谢任何看这个问题的人。

问题:

我有一段遗留代码需要为其编写测试(我们正在尝试围绕继承的代码进行测试,以确保我们在潜在的大规模重构工作中不会破坏任何东西......那是另一个故事了.)

目标:

我试图模拟的方法是下面类中的 Foo.bar 方法,它使用 JMock 的类冒名顶替者工具(通过 JUnit4Mockery 。)

下面的代码是我正在测试包装的代码的代表:

public class Foo {
public abstract <T> void bar(
Class<? extends T> paramClass, T paramT);

我的测试设置旨在允许对 bar() 的任何调用接收一个 Class 实例(这显然退化为 Class ...愚蠢的 Java 类型删除“功能”),与任何实例配对Snafu 的。

这是这里的关键区别。我没有配对两个 Matcher参数,或两个文字参数,但一个文字 (T.class) 和类型 T 的任何值。JMock 不允许这样做,因此预期的解决方案 将是有一个 Matcher> 和一个 Matcher:

Foo mock = context.mock(Foo.class);
context.checking(new Expectations() {
// keep warnings close to the culprit code when possible
@SuppressWarnings("unchecked")
public void allow(final Foo mockedFoo) {
allowing(mockedFoo).bar(
with(any(Snafu.class.getClass())), // Matcher that *should* resolve to Class<?>
with(any(Snafu.class))); // matcher to anything of type Snafu.class
}
{
allow(mockedFoo);
}
});

然后,我们注入(inject)模拟的 Foo,它最终被另一个类这样调用,我将其称为 Driver(*我稍后会回到静态方法调用):

// fooImpl has been replaced/injected with our mock
fooImpl.bar(Snafu.class, someStaticFunctionThatReturnsASnafu());

问题:

问题是当 Driver 在模拟的 Foo 实例上调用 bar 方法时,我的测试遇到以下异常:

java.lang.IllegalArgumentException: not all parameters were given explicit matchers: either all parameters must be specified by matchers or all must be specified by values, *you cannot mix matchers and values*
at org.jmock.internal.InvocationExpectationBuilder.checkParameterMatcherCount(InvocationExpectationBuilder.java:98)
at org.jmock.internal.InvocationExpectationBuilder.createExpectationFrom(InvocationExpectationBuilder.java:91)
at org.jmock.internal.InvocationToExpectationTranslator.invoke(InvocationToExpectationTranslator.java:19)
at org.jmock.internal.FakeObjectMethods.invoke(FakeObjectMethods.java:38)
at org.jmock.lib.legacy.ClassImposteriser$4.invoke(ClassImposteriser.java:129)
at .....

显然(或者在我看来),JMock 匹配器将 Class 实例视为值,无论我们如何尝试匹配它们。还是我遗漏了什么?

我在许多采用 java.lang.Class 参数的遗留调用中遇到了类似的异常。显然,任何看起来像 X.class 的东西都将是一个值,而不是一个新实例。

但这就是问题所在,因为另一个参数必须用匹配器来解决,而不仅仅是用实际值。


[*] 理想情况下,可以重写

中的静态方法调用
fooImpl.bar(Snafu.class, someStaticFunctionThatReturnsASnafu()); 

用更适合模拟的东西(非静态方法、另一个对象或用 IoC 注入(inject)的东西)。

可能这就是我们最终要走的路,但就目前而言,有问题的代码有大量的静态调用。

我想把它推迟到更合适的时刻,而不是找到一个通用的 JMock 解决方案,如果存在的话,它允许我设置模拟函数的必要期望,比如 Foo.bar以上。

最佳答案

如果我没记错的话,您在测试用例中所做的一切都是正确的。 documentation关于 with 子句状态的 JMock

An expectation that uses parameter matchers must use the "with" method to wrap every parameter, whether a matcher function or a literal value.

这里重要的部分是强调every。你应该只得到你提到的 IllegalArgumentException

java.lang.IllegalArgumentException: not all parameters were given explicit matchers: either all parameters must be specified by matchers or all must be specified by values, you cannot mix matchers and values

如果您将 with 子句与文字值混合使用 - 在您的例子中

allowing(mockedFoo).bar(Class.class, with(any(Snafu.class)));

其中 Class.class 是文字值。另见 here .

我测试了您的代码,它似乎按预期工作。这是我完整的 JUnit TestCase:

import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.integration.junit4.JUnit4Mockery;
import junit.framework.TestCase;

public class FooTest extends TestCase{
Mockery context = new JUnit4Mockery();

public interface Foo {
public abstract <T> void bar(Class<? extends T> paramClass, T paramT);
}

public static class Snafu {}

public void testFoo() {
final Foo mock = context.mock(Foo.class);
context.checking(new Expectations() {
// keep warnings close to the culprit code when possible
@SuppressWarnings("unchecked")
public void allow(final Foo mockedFoo) {
allowing(mockedFoo).bar(
with(any(Class.class)), // Matcher that *should* resolve to Class<?>
with(any(Snafu.class))); // matcher to anything of type Snafu.class
}
{
allow(mock);
}
});

// test bar method (two invocations)
mock.bar(Snafu.class, someStaticFunctionThatReturnsASnafu());
mock.bar(Snafu.class, someStaticFunctionThatReturnsASnafu());

}

public static Snafu someStaticFunctionThatReturnsASnafu() {
return new Snafu();
}
}

此测试用例成功,没有任何运行时异常(使用 JUnit 4 和 JMock 2.6.0 测试)。为了可读性,我使用了 with(any(Class.class)) 而不是 with(any(Snafu.class.getClass())) ,但这并不重要.

如果我将其更改为

,我只会得到提到的 IllegalArgumentException
allowing(mockedFoo).bar(Class.class, with(any(Snafu.class)));

关于java - 使用 JMock 的类 <?> 类型参数的模拟方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22842572/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com