如何确保实例没有被调用的方法?
我的代码中有几个small dieties,在测试时会引起痛苦。假设将这些小神化为碎片对于这个练习来说太费力了。如何确保实例没有被调用的方法?
通常的问题是,我想测试的方法的Foo
x()
而是创造的Foo
一个实例,我需要定义N(1 <Ñ< 10)的模拟实例,其是仅存在满足Spring的@Autowire
。在生产中,我必须确定这些字段是有线的,因此使这些选项不是一种选择。
可能的解决方案我看到:
- 告诉春不知何故,一些
@Autowire
字段都是可选的测试期间 - 通在uncallable嘲笑任何东西所测试的代码不会/不应该”需要。
因为我不知道做#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
的方法,但会返回“不要代之以叫我“代理。
我对这个领域还比较陌生,但我认为Spring的整个想法是,它很容易替换测试和其他环境变化。从认为他理解概念但没有实现任何主要内容的人的角度来看待它,这有什么问题:每个自动布线都是一个接口。设想一个实现这个接口的类,其中每个方法只是调用某种错误报告机制 - 对于所有这些方法可以是相同的。创建这样一个类(手工)应该很快,而不是容易出错,现在你有了'模拟'。如果你有10个这样的人,那么为他们每个人创造一个这样的班级都不需要很长时间。
现在创建一个弹簧配置文件,传递给定的一组测试所需的这些模拟对象。如果有人称之为模拟类,它会吐出上述错误。当然,对于不同的测试环境,不同的配置可以包括不同的模拟。
我在这里错过了什么?
我可以手动完成所有这些工作,或让一个程序为我完成。我的观点是,编写这些代码很容易;我只是不知道如何适应Spring的BeanFactory API。 – 2013-03-01 12:52:04
黄金的道路是:不要在你的测试中使用Spring,只需用普通的香草java代码设置你的依赖。如果这是痛苦的,你有一个强大的指标如何重构你的代码。这是一件好事。对于不应该被调用的依赖关系,您可以提供在每个方法调用时都会爆炸的嘲笑。一个简单的方法来实现,这应该是这个漂亮的功能的Mockito:http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#14
肮脏的路径:如果一个在旧沼泽被困在那里你可以不忍心安装测试中的所有的依赖(和未成年人的存在神是一个指标),你可以使用SpringJUnit4ClassRunner
+ Spring配置文件(如果你使用Spring 3.1或更高版本,我认为)。
使用此功能,您可以使用例如prod
配置文件,该配置文件用于生产环境,配置文件用于替换所有必须用mock调用的bean,如上所述。 Google针对各种教程的“spring + profiles”。它很容易,像魅力一样工作......但只适用于你想要替换的一组固定豆。如果你有50个测试,每个都需要20个不同的子集,用吹响的豆子取代20个豆子,它会变得更糟:
地狱般的路径:使用Spring,但用一个特定的bean集合替换在每个测试级别上开启即时通话豆。您可以通过具有特殊的上下文配置来完成该任务,该配置包含要替换的单个bean的配置。它必须与生产bean具有相同的名称/ ID,但是会打开调用实现(如果你喜欢,也可以通过Mockito)。在每个测试你再使用ContextConfiguration注释如下所示:
@ContextConfiguration(locations = {"applicationContext.xml", "blowUpDemiGod42.xml",
"blowUpDemiGod23.xml"})
这将使配置在blowUpDemiGod*.xml
文件将覆盖从applicationContext.xml
的配置有可能是地狱之路的光形式,你可以通过Java代码在测试中提供bean ...不确定。
我喜欢Mockito功能,因为我已经将其用于其他测试...... Mockito只有太多功能;-)但真的没有办法创建“自动构建器BeanFactory”吗? – 2013-03-01 12:54:15
为什么你特别需要一个bean工厂?我通常希望你在不使用任何自动装配的情况下测试代码*只需将值传递给正常的构造函数(或设置属性)即可。因此,正常的严格模拟(例如通过Mockito或EasyMock)应该没问题。 – 2013-02-28 14:20:42
你的春天版本是3.0.X吗?从3.1.X版本开始,spring支持[profiles](http://blog.springsource.org/2011/02/14/spring-3-1-m1-introducing-profile/),它们可能对你有帮助。 – n1ckolas 2013-02-28 14:22:13
我使用Spring 3.2和Mockito,如果有帮助。 – 2013-03-01 12:50:03