技术开发 频道

详细讲解在Spring中进行集成测试

在不提供Setter方法的情况下自动注入

大多数IDE都提供了为属性变量自动生成Setter方法的操作,因此客观地说,为属性编写一个Setter方法的工作根本不值一提。如果你觉得众多的Setter方法影响了视觉感观,但又希望享受测试类属性自动装配的好处,Spring也不会让你失望的。你需要做的是以下两步的工作:
1) 将需要自动装配的属性变量声明为protected;
2) 在测试类构造函数中调用setPopulateProtectedVariables(true)方法。
package com.baobaotao.test; … public class DependencyInjectionCtxTest extends AbstractDependencyInjectionSpringContextTests { protected UserService userService; ①将属性声明为protected // public void setUserService(UserService userService) { ②大胆将Setter方法移除掉 // this.userService = userService; // } public DependencyInjectionCtxTest(){ setDependencyCheck(false); setPopulateProtectedVariables(true); ③启用直接对属性变量进行注释的机制 } … }

将属性声明为protected后并通过setPopulateProtectedVariables(true)启用对属性变量直接注入的机制(启用反射机制注入),你就可以避免为属性变量编写对应的Setter方法了。

提示 属性如果声明为public,虽然你也调用了setPopulateProtectedVariables(true)方法,属性变量依然不会被自动注入。所以这种机制仅限于protected的属性变量。

方便地恢复测试数据库现场

我们现在已经可以通过AbstractDependencyInjectionSpringContextTests的属性自动装配机制方便地建立起测试固件,省却手工调用getBean()自行准备测试固件的烦恼。当我们对UserService的hasMatchUser()和findUserByUserName()方法进行测试时,不会有任何问题,因为这两个方法仅对数据库执行读操作。但UserService以下两个接口方法会对数据库执行更改操作:

void loginSuccess(User user); void registerUser(User user);

当我们对这两个接口方法进行测试时,它们将会在数据库中产生持久化数据。考虑对registerUser(User user)方法进行测试时,我们可能编写如下所示的测试方法:

public void testRegisterUser(){ User user = new User(); user.setUserId(2); user.setUserName("john"); user.setPassword("123456"); userService.registerUser(user); }

当第一次成功运行testRegisterUser()测试方法时,将在数据库中产生一条主键为2的记录,如何第二次重新运行testRegisterUser()测试方法其结果将不言自明:因主键冲突导致测试方法执行失败,最终报告测试用例没有通过。在这种情况下,测试用例未通过并不是因为UserServiceImpl#registerUser(User user)存在逻辑错误,而是因为测试方法的积累效应导致外在设施的现场发生变化而引起的问题。

为了防止这种问题,测试用例必须在保证不对数据库状态产生持久化变化的情况下,对目标类的数据操作逻辑正确性进行检测。乍一听这一要求有点貌似于“既想马儿跑,又想马儿不吃草”一样充满悖论,实则不然。只要我们让测试方法不提交事务,在测试完后自动回滚事务,就皆大欢喜了。

0
相关文章