想要不那么Bad smell 的 UnitTest真不容易

自打用Maven做项目管理之后,直接和UnitTest接触的次数增加,原以为已经三令五申要重视的测试总有那么一股bad smell,开始反思底层或者外围辅助不足,导致开发人员写测试代码压力大,决定着手改善。

 

一、测试工具由JUnit向TestNG转移

    一直用Eclipse自带的JUnit工具,简单方便没得说,但几个有缺憾的地方一直不能改进。一个是static的BeforeClass、AfterClass,这已经臭名远播了,不多说。另一个是没有灵活的分组,为下一步要提到的分组测试带来不少麻烦。这两方面恰恰是TestNG的强项,非static的Before、After,可分组测试,甚至提供线程压力测试的控制等等一堆功能。缺点也有,Eclipse插件做的粗糙,创建Test类比Junit差了几个档次,基本信息都要手填,更没有对测试方法的选择和自动生成。权衡利弊还是坚持选择了TestNG

 

二、Dao层测试用不用DBUnit

    DBUnit可以方便的完成备份表,插入测试数据,实际使用发现如果有外键关联表会有不少麻烦,往往对一个表的测试需要备份、创建N多关联表,再加上使用复杂sql、存储过程的场景,个人倾向DBUnit不强制使用。同时Dao层测试统一group(testNG的好处)

 

@Test(groups = { "dao" })

方便做有选择的测试 

 

 

三、Mock测试

    一般的Web开发其他层次都可以用Mock做到隔离Dao层,个人习惯用JMock,与TestNG配合良好,各种支持完善。

 

Mockery context = new Mockery();
UserService service = new UserServiceImpl();
UserDao userDao = context.mock(UserDao.class);
((UserServiceImpl) service).setUserDao(userDao);

final User user = new User();
user.setId("123");
context.checking(new Expectations() {
	{
		(allowing(userDao)).getUserById("123");
		will(returnValue(user));
		(allowing(userDao)).getUserById("124");
		will(returnValue(null));
	}
});
 

 

    Service层可以轻松应付,完全独立测试,有麻烦的往往在Action层。基于Spring的AppliactionContext在Aciton内部getBean调用Service,造成在UnitTest中没有机会Mock,最后只好Mock掉ApplicationContext

 

ApplicationContext orgContext = SomeContainer.getApplicationContext();
ApplicationContext mockContext = context.mock(ApplicationContext.class);
context.checking(new Expectations() {
	{
		(allowing(mockContext)).getBean("userService", UserService.class);
		will(returnValue(service));
		(allowing(mockContext)).getBean(with(any(String.class)),
				with(any(Class.class)));
		will(new CustomAction("original getBean") {
			@Override
			public Object invoke(Invocation invocation) throws Throwable {
				return orgContext.getBean((String) invocation.getParameter(0),
						(Class<?>) invocation.getParameter(1));
			}
		});
	}
});

 

 针对Action逻辑,mock调用的Service,事后把mockContext植入到框架中。

常规的Action测试照旧,各种Mock,核对结果。

 

@Test(groups = { "action" })

 

 

四、整合的Test

   项目内使用同一的测试基类,把配置导入之类的工作统统接管,减轻测试类压力,要注意全局导入方法要加上

@BeforeSuite(alwaysRun = true)

 testsuite.xml可以有选择的执行某些group或全执行

<suite name="someproject" verbose="1">
	<test name="testPackage">
		<packages>
			<package name="cn.com.xxx.yyy.zzz.test.*" />
		</packages>
	</test>
</suite>

 maven配置做个简单指定

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-surefire-plugin</artifactId>
	<version>2.6</version>
	<configuration>
		<skipTests>false</skipTests>
		<includes>
			<include>**/*Test.java</include>
		</includes>
		<!-- <groups>dao,action</groups>根据需要测试某些group -->
		<suiteXmlFiles>  <suiteXmlFile>src/test/resources/testsuite.xml</suiteXmlFile>
		</suiteXmlFiles>
	</configuration>
</plugin>
 

 

你可能感兴趣的:(DAO,eclipse,spring,maven,JUnit)