- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
这是一个 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/
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!