【发布时间】:2013-02-28 14:17:03
【问题描述】:
我的代码中有几个small dieties 在测试时会引起痛苦。假设将小神打成碎片对于这个练习来说太费力了。
通常的问题是我想测试 Foo 的方法 x() 但要创建 Foo 的实例,我需要定义 N (1 @Autowire。在生产中,我必须确保这些字段是连线的,因此不能选择这些字段。
我看到的可能解决方案:
- 以某种方式告诉 Spring 一些
@Autowire字段在测试期间是可选的 - 为被测代码不需要/不应该需要的任何内容传递不可调用的模拟。
由于我不知道#1 的方法,我认为#2 是要走的路。我更喜欢的是一个 bean 工厂,它返回一个代理,该代理会为我未定义的任何 bean 的任何方法调用引发异常。
所以对于任何未知的bean,它应该调用这个create方法:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MustNotCallMe {
@SuppressWarnings( "unchecked" )
public static <T> T create( final Class<T> type, final Class<?>... types ) {
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable {
if( "equals".equals( method.getName() ) && Object.class.equals( method.getDeclaringClass() ) ) {
return proxy == args[0];
}
throw new UnsupportedOperationException( "You must not call " + method );
}
};
Class<?>[] allClasses = new Class<?>[ types.length + 1 ];
allClasses[0] = type;
System.arraycopy( types, 0, allClasses, 1, types.length );
return (T) Proxy.newProxyInstance( MustNotCallMe.class.getClassLoader(), allClasses, handler );
}
}
这样的东西存在吗?如果没有,我将如何在 Spring 3 单元测试中注入我自己的 bean 工厂?
编辑我知道这个想法会让任何语言纯粹主义者感到不安。只有现实很少是纯粹的。如果这里有人愿意站出来为我们提供重构软件所需的资金和人力,我们很乐意听到。在那之前,无需大量手动工作即可解决问题的解决方案可以更好地解决我们的特定问题:-)
也就是说,我只需要一种方法来创建一个 BeanFactory,它永远不会抛出 NoSuchBeanException,而是返回一个“不要打电话给我”的代理。
【问题讨论】:
-
为什么特别需要豆厂?我通常希望您使用任何自动装配来测试代码而不使用 - 只需将值传递给普通的构造函数(或设置属性)。因此,正常的严格模拟(例如通过 Mockito 或 EasyMock)应该没问题。
-
你的 spring 版本是 3.0.X 吗?从 3.1.X 版本开始,spring 支持profiles,它们可能对您有所帮助。
-
我正在使用 Spring 3.2 和 Mockito,如果有帮助的话。
-
@JonSkeet:我也喜欢这样,但是代码变得太复杂了,我们现在没有人手来修复它,所以我会接受第二好的解决方案。
标签: java unit-testing mocking