我正在开发一个Spring MVC项目,并且我对源代码树中的所有各种组件进行了单元测试。
例如,如果我有一个控制器HomeController
,需要注入LoginService
,那么在我的单元测试中HomeControllerTest
我只是将对象实例化为正常(外部) of Spring)并注入属性:
protected void setUp() throws Exception {
super.setUp();
//...
controller = new HomeController();
controller.setLoginService( new SimpleLoginService() );
//...
}
这对于将每个组件作为一个独立的单元进行测试非常有用 - 除了现在我在项目中有几十个类,在编写一个类并为它编写成功的单元测试后,我一直忘记更新我的Spring MVC上下文在已部署的应用程序中进行实际连接的文件。我发现当我将项目部署到Tomcat并从非有线bean中找到一堆NullPointers时,我忘记更新上下文文件。
所以,这是我的问题:
这是我的第一个Spring项目 - 正如我所做的那样,为单个bean创建单元测试是正常的,然后创建第二套测试(集成测试)来测试一切是否按预期工作实际的应用背景?是否有既定的最佳实践?
此外,您如何将单元测试与集成测试分开?我有src
中的所有源代码,test
中的单元测试 - 是否应该有第二个测试文件夹(例如test-integration
)用于集成测试用例?
由于这是我的第一个春季项目,我很好奇其他人通常会如何做这类事情 - 而不是重新发明轮子我宁愿问社区其他人。
答案 0 :(得分:32)
我不能说是最佳实践,但这是我过去所做的。
单元测试:
test
目录中对这些测试使用标准命名约定。使用Test
或TestCase
作为类名的前缀或后缀似乎已被广泛使用。整合测试:
AbstractIntegrationTestCase
,设置Spring
WebApplicationContext
以用于集成测试条款。test
目录中使用命名约定进行集成测试。我已使用IntTest
或IntegrationTest
作为这些测试的前缀或后缀。设置三个Ant test
目标:
test
似乎是单元测试的最常见用法如上所述,您可以使用对您的项目有意义的命名约定。
至于将单元从集成测试分离到一个单独的目录中,只要开发人员及其工具可以轻松找到并执行它们,我认为这不重要。
作为一个例子,我使用Spring工作的最后一个Java项目完全使用了上面描述的内容,集成测试和单元测试位于同一个test
目录中。另一方面,Grails项目明确地将通用测试目录下的单元和集成测试目录分开。
答案 1 :(得分:6)
一些孤立的观点:
是的,这是Spring测试的常用方法 - 单独的单元测试和集成测试,前者不加载任何Spring上下文。
对于您的单元测试,可以考虑进行模拟以确保您的测试集中在一个隔离模块上。
如果你的测试是依赖大量的依赖,那么它们就不是真正的单元测试。它们是集成测试,您可以使用new而不是依赖注入来连接依赖项。当您的生产应用程序使用Spring时浪费时间和重复工作!
用于调出Spring上下文的基本集成测试非常有用。
@required注释可以帮助您确保在Spring连线中捕获所需的依赖项。
也许看看Maven会给你明确的阶段来绑定你的单位和集成测试。 Maven在Spring社区中得到了广泛的应用。
答案 2 :(得分:4)
如果你也转换到一个纯粹注释的制度,你可以用@ Component,@ Controller,@ Service和@Repository注释你所有的bean,那么很多繁琐的春季双书保存就会消失。只需将@Autowired添加到您需要注入的属性中。
参见弹簧参考手册的3.11节。 http://static.springframework.org/spring/docs/2.5.x/reference/beans.html#beans-annotation-config
在相关的说明中,我们一直在使用KenG描述的Unit / Integratrion分区测试。在我最近的政权中,我们还引入了第三个“类”测试,“ComponentTests”。它们采用全弹簧布线,但采用有线短线实现(使用弹簧中的元件扫描滤波器和注释)。
我们这样做的原因是因为对于某些“服务”层,你最终会得到大量的手工编码布线逻辑来手动连接bean,有时甚至是荒谬的模拟对象。用于5行测试的100条线路并不罕见。组件测试缓解了这个问题。
答案 3 :(得分:2)
使用InitializingBean接口(实现方法“afterPropertiesSet”)或为bean指定init方法。 InitializingBean通常更容易,因为您不需要记住将init方法添加到bean中。
使用afterPropertiesSet确保所有内容都注入为非null,如果为null,则抛出异常。
答案 4 :(得分:0)
当我为Web应用程序创建集成测试时,我将它们放在一个单独的目录中。它们是使用jUnit或TestNG构建的,并使用Selenium之类的东西与被测系统进行交互,这些内容就像用户一样点击网页。循环将如下所示:编译,运行单元测试,构建Web应用程序,将其部署到正在运行的服务器,执行测试,取消部署应用程序以及报告结果。这个想法是测试整个系统。
答案 5 :(得分:0)
关于与集成测试分开运行单元测试,我将所有后者放入集成测试目录,并使用类似this的方法使用IDE / Ant运行它们。适合我。
答案 6 :(得分:0)
单元测试和集成测试之间的区别在于,单元测试不一定加载你的上下文,你专注于你编写的代码 - 它通过模拟任何依赖调用快速失败,即有和没有例外在里面。 但是在集成测试的情况下,您可以加载上下文并像实际场景一样执行端到端测试。