加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 使用JMock键入参数的模拟方法

发布时间:2020-12-14 05:12:42 所属栏目:Java 来源:网络整理
导读:背景: 这是一个JMock JUnit具体的问题(这些是我必须使用的两种技术).是的,我想做的是用PowerMock做的,但这是一个不值得改变工具的边缘案例.不,对不起,我不是问这个问题来辩论静态方法的哲学有效性:) 有了这个,我真的很感谢任何人看这个问题. 题: 我有一些
背景:

这是一个JMock JUnit具体的问题(这些是我必须使用的两种技术).是的,我想做的是用PowerMock做的,但这是一个不值得改变工具的边缘案例.不,对不起,我不是问这个问题来辩论静态方法的哲学有效性:)

有了这个,我真的很感谢任何人看这个问题.

题:

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

目标:

我试图模拟的方法是下面类中的Foo.bar方法,使用JMock的类imposterizer设施(通过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>和匹配者:

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

然后,我们注入嘲笑的Foo,最终被另一个类调用,我将被称为驱动程序(*我稍后会回到静态方法调用):

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

问题:

问题是当驱动程序在嘲笑的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的东西).

可能这是我们最终会走的方式,但是暂时的代码有很多静态调用.

我想推迟,直到一个更适当的时刻,而是找到一个通用的JMock解决方案,如果存在,这允许我设置愚蠢的功能,如上面的Foo.bar的必要期望.

解决方法

如果我没有错,你在你的测试案例中做了一切. JMock的 documentation关于条款的条款

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

这里的重要部分是强调每一个.你应该只得到你提到的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

如果你将一个条款与一个字面值混合在一起 – 在你的情况下

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进行测试).我使用(任何(Class.class))而不是(任何(Snafu.class.getClass()))可读性,但并不重要.

我只得到提到的IllegalArgumentException,如果我把它改为

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读