Junit使用教程(四)

来源:互联网 发布:ubuntu安装app 编辑:程序博客网 时间:2024/05/16 17:28

一、会用Spring测试套件的好处

在开发基于Spring的应用时,如果你还直接使用Junit进行单元测试,那你就错过了Spring为我们所提供的饕餮大餐了。使用Junit直接进行单元测试有以下四大不足:

1)导致多次Spring容器初始化问题

根据JUnit测试方法的调用流程,每执行一个测试方法都会创建一个测试用例的实例并调用setUp()方法。由于一般情况下,我们在setUp()方法中初始化Spring容器,这意味着如果测试用例有多少个测试方法,Spring容器就会被重复初始化多次。虽然初始化Spring容器的速度并不会太慢,但由于可能会在Spring容器初始化时执行加载Hibernate映射文件等耗时的操作,如果每执行一个测试方法都必须重复初始化Spring容器,则对测试性能的影响是不容忽视的;

使用Spring测试套件,Spring容器只会初始化一次

2)需要使用硬编码方式手工获取Bean

在测试用例类中我们需要通过ctx.getBean()方法从Spirng容器中获取需要测试的目标Bean,并且还要进行强制类型转换的造型操作。这种乏味的操作迷漫在测试用例的代码中,让人觉得烦琐不堪;

使用Spring测试套件,测试用例类中的属性会被自动填充Spring容器的对应Bean,无须在手工设置Bean!

3)数据库现场容易遭受破坏

测试方法对数据库的更改操作会持久化到数据库中。虽然是针对开发数据库进行操作,但如果数据操作的影响是持久的,可能会影响到后面的测试行为。举个例子,用户在测试方法中插入一条ID为1的User记录,第一次运行不会有问题,第二次运行时,就会因为主键冲突而导致测试用例失败。所以应该既能够完成功能逻辑检查,又能够在测试完成后恢复现场,不会留下“后遗症”;

使用Spring测试套件,Spring会在你验证后,自动回滚对数据库的操作,保证数据库的现场不被破坏,因此重复测试不会发生问题!

4)不方便对数据操作正确性进行检查

假如我们向登录日志表插入了一条成功登录日志,可是我们却没有对t_login_log表中是否确实添加了一条记录进行检查。一般情况下,我们可能是打开数据库,肉眼观察是否插入了相应的记录,但这严重违背了自动测试的原则。试想在测试包括成千上万个数据操作行为的程序时,如何用肉眼进行检查?

只要你继承Spring的测试套件的用例类,你就可以通过jdbcTemplate(或Dao等)在同一事务中访问数据库,查询数据的变化,验证操作的正确性!

Spring提供了一套扩展于Junit测试用例的测试套件,使用这套测试套件完全解决了以上四个问题,让我们测试Spring的应用更加方便。这个测试套件主要由org.springframework.test包下的若干类组成,使用简单快捷,方便上手。

二、使用方法

1)基本用法

[java] view plaincopy
  1. package com.test;  
  2.   
  3. import javax.annotation.Resource;  
  4.   
  5. import org.junit.Test;  
  6. import org.junit.runner.RunWith;  
  7. import org.springframework.test.context.ContextConfiguration;  
  8. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
  9.   
  10. @RunWith(SpringJUnit4ClassRunner.class)  
  11. @ContextConfiguration(locations = { "classpath:config/applicationContext-*.xml""classpath:services/ext/service-*.xml" })  
  12. public class UserServiceTest {  
  13.   
  14.     @Resource  
  15.     private IUserService userService;  
  16.   
  17.     @Test  
  18.     public void testAddOpinion1() {  
  19.         userService.downloadCount(1);  
  20.         System.out.println(1);  
  21.     }  
  22.   
  23.     @Test  
  24.     public void testAddOpinion2() {  
  25.         userService.downloadCount(2);  
  26.         System.out.println(2);  
  27.     }  
  28. }  

@RunWith(SpringJUnit4ClassRunner.class) 用于配置spring中测试的环境

@ContextConfiguration(locations = { "classpath:config/applicationContext-*.xml", "classpath:services/ext/service-*.xml" })用于指定配置文件所在的位置

@Resource注入Spring容器Bean对象,注意与@Autowired区别

2)事务用法

[java] view plaincopy
  1. package com.test;  
  2.   
  3. import javax.annotation.Resource;  
  4.   
  5. import org.junit.Test;  
  6. import org.junit.runner.RunWith;  
  7. import org.springframework.test.annotation.Rollback;  
  8. import org.springframework.test.context.ContextConfiguration;  
  9. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
  10. import org.springframework.test.context.transaction.TransactionConfiguration;  
  11. import org.springframework.transaction.annotation.Transactional;  
  12.   
  13. @RunWith(SpringJUnit4ClassRunner.class)  
  14. @ContextConfiguration(locations = { "classpath:config/applicationContext-*.xml""classpath:services/ext/service-*.xml" })  
  15. @Transactional  
  16. @TransactionConfiguration(transactionManager = "transactionManager")  
  17. //@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)  
  18. public class UserServiceTest {  
  19.   
  20.     @Resource  
  21.     private IUserService userService;  
  22.   
  23.     @Test  
  24. //  @Transactional  
  25.     public void testAddOpinion1() {  
  26.         userService.downloadCount(1);  
  27.         System.out.println(1);  
  28.     }  
  29.   
  30.     @Test  
  31.     @Rollback(false)  
  32.     public void testAddOpinion2() {  
  33.         userService.downloadCount(2);  
  34.         System.out.println(2);  
  35.     }  
  36. }  

@TransactionConfiguration(transactionManager="transactionManager")读取Spring配置文件中名为transactionManager的事务配置,defaultRollback为事务回滚默认设置。该注解是可选的,可使用@Transactional与@Rollback配合完成事务管理。当然也可以使用@Transactional与@TransactionConfiguration配合。

@Transactional开启事务。可放到类或方法上,类上作用于所有方法。

@Rollback事务回滚配置。只能放到方法上。

3)继承AbstractTransactionalJUnit4SpringContextTests

[java] view plaincopy
  1. package com.test;  
  2.   
  3. import javax.annotation.Resource;  
  4.   
  5. import org.junit.Test;  
  6. import org.springframework.test.context.ContextConfiguration;  
  7. import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;  
  8. import org.springframework.test.context.transaction.TransactionConfiguration;  
  9.   
  10. @ContextConfiguration(locations = { "classpath:config/applicationContext-*.xml""classpath:services/ext/service-*.xml" })  
  11. @TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)  
  12. public class UserServiceTest extends AbstractTransactionalJUnit4SpringContextTests {  
  13.   
  14.     @Resource  
  15.     private IUserService userService;  
  16.   
  17.     @Test  
  18.     public void testAddOpinion1() {  
  19.         userService.downloadCount(1);  
  20.         System.out.println(1);  
  21.     }  
  22.   
  23.     @Test  
  24.     public void testAddOpinion2() {  
  25.         userService.downloadCount(2);  
  26.         System.out.println(2);  
  27.     }  
  28. }  

AbstractTransactionalJUnit4SpringContextTests:这个类为我们解决了在web.xml中配置OpenSessionInview所解决的session生命周期延长的问题,所以要继承这个类。该类已经在类级别预先配置了好了事物支持,因此不必再配置@Transactional和@RunWith

4)继承

[java] view plaincopy
  1. package com.test;  
  2.   
  3. import org.springframework.test.context.ContextConfiguration;  
  4. import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;  
  5. import org.springframework.test.context.transaction.TransactionConfiguration;  
  6.   
  7. @ContextConfiguration(locations = { "classpath:config/applicationContext-*.xml""classpath:services/ext/service-*.xml" })  
  8. @TransactionConfiguration(transactionManager = "transactionManager")  
  9. public class BaseTestCase extends AbstractTransactionalJUnit4SpringContextTests {  
  10.   
  11. }  
[java] view plaincopy
  1. package com.test;  
  2.   
  3. import javax.annotation.Resource;  
  4.   
  5. import org.junit.Test;  
  6. import org.springframework.test.annotation.Rollback;  
  7.   
  8. public class UserServiceTest extends BaseTestCase {  
  9.   
  10.     @Resource  
  11.     private IUserService userService;  
  12.   
  13.     @Test  
  14.     public void testAddOpinion1() {  
  15.         userService.downloadCount(1);  
  16.         System.out.println(1);  
  17.     }  
  18.   
  19.     @Test  
  20.     @Rollback(false)  
  21.     public void testAddOpinion2() {  
  22.         userService.downloadCount(2);  
  23.         System.out.println(2);  
  24.     }  
  25. }  

5)综合

[java] view plaincopy
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @ContextConfiguration  
  3. @TransactionConfiguration  
  4. @Transactional  
  5. public class PersonDaoTransactionUnitTest extends AbstractTransactionalJUnit4SpringContextTests {  
  6.   
  7.     final Logger logger = LoggerFactory.getLogger(PersonDaoTransactionUnitTest.class);  
  8.   
  9.     protected static int SIZE = 2;  
  10.     protected static Integer ID = new Integer(1);  
  11.     protected static String FIRST_NAME = "Joe";  
  12.     protected static String LAST_NAME = "Smith";  
  13.     protected static String CHANGED_LAST_NAME = "Jackson";  
  14.   
  15.     @Autowired  
  16.     protected PersonDao personDao = null;  
  17.   
  18.     /** 
  19.      * Tests that the size and first record match what is expected before the transaction. 
  20.      */  
  21.     @BeforeTransaction  
  22.     public void beforeTransaction() {  
  23.         testPerson(true, LAST_NAME);  
  24.     }  
  25.   
  26.     /** 
  27.      * Tests person table and changes the first records last name. 
  28.      */  
  29.     @Test  
  30.     public void testHibernateTemplate() throws SQLException {  
  31.         assertNotNull("Person DAO is null.", personDao);  
  32.   
  33.         Collection<Person> lPersons = personDao.findPersons();  
  34.   
  35.         assertNotNull("Person list is null.", lPersons);  
  36.         assertEquals("Number of persons should be " + SIZE + ".", SIZE, lPersons.size());  
  37.   
  38.         for (Person person : lPersons) {  
  39.             assertNotNull("Person is null.", person);  
  40.   
  41.             if (ID.equals(person.getId())) {  
  42.                 assertEquals("Person first name should be " + FIRST_NAME + ".", FIRST_NAME, person.getFirstName());  
  43.                 assertEquals("Person last name should be " + LAST_NAME + ".", LAST_NAME, person.getLastName());  
  44.   
  45.                 person.setLastName(CHANGED_LAST_NAME);  
  46.   
  47.                 personDao.save(person);  
  48.             }  
  49.         }  
  50.     }  
  51.   
  52.     /** 
  53.      * Tests that the size and first record match what is expected after the transaction. 
  54.      */  
  55.     @AfterTransaction  
  56.     public void afterTransaction() {  
  57.         testPerson(false, LAST_NAME);  
  58.     }  
  59.   
  60.     /** 
  61.      * Tests person table. 
  62.      */  
  63.     protected void testPerson(boolean beforeTransaction, String matchLastName) {  
  64.         List<Map<String, Object>> lPersonMaps = simpleJdbcTemplate.queryForList("SELECT * FROM PERSON");  
  65.   
  66.         assertNotNull("Person list is null.", lPersonMaps);  
  67.         assertEquals("Number of persons should be " + SIZE + ".", SIZE, lPersonMaps.size());  
  68.   
  69.         Map<String, Object> hPerson = lPersonMaps.get(0);  
  70.   
  71.         logger.debug((beforeTransaction ? "Before" : "After") + " transaction.  " + hPerson.toString());  
  72.   
  73.         Integer id = (Integer) hPerson.get("ID");  
  74.         String firstName = (String) hPerson.get("FIRST_NAME");  
  75.         String lastName = (String) hPerson.get("LAST_NAME");  
  76.   
  77.         if (ID.equals(id)) {  
  78.             assertEquals("Person first name should be " + FIRST_NAME + ".", FIRST_NAME, firstName);  
  79.             assertEquals("Person last name should be " + matchLastName + ".", matchLastName, lastName);  
  80.         }  
  81.     }  
  82.   
  83. }  

@BeforeTransaction在事务之前执行

@AfterTransaction在事务之后执行

@NotTransactional不开启事务

 

好了,本篇作为Junit补充就说到这里了,希望大家多多分享经验哦。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 宝宝到陌生地方哭闹怎么办 大人生病住院小孩没人带怎么办 孕妇被小猫抓了怎么办 怀孕了家里有猫怎么办 厕所被湿纸巾堵了怎么办 5天新生儿不拉屎怎么办 4月宝宝不拉屎怎么办 两岁宝宝晚上睡觉哭闹怎么办 2月婴儿吐奶很多怎么办 心情不好回奶了怎么办 四个月了没奶怎么办 八岁宝宝还尿床怎么办 自己一人在家害怕怎么办 被猫抓伤流血了怎么办 被小狐狸咬了怎么办 怀孕吃了兔子肉怎么办 鸟总在窗子上啄怎么办? 有鸟飞进楼道里怎么办 租的房间房东要求改建怎么办 小偷偷钱抓住不还钱怎么办 损友圈羊被陌生人偷了怎么办 在酒店如果遇到客人偷东西怎么办 梦见家里有不好的东西怎么办 被小孩要破了怎么办啊 租一个房子小孩一进房就哭怎么办 墙缝里有蝙蝠窝怎么办 小蝙蝠在墙缝里怎么办 小孩一进屋就哭怎么办 屋门对着厕所门怎么办 入室门对厨房门怎么办 厕所正对入户门怎么办 小区楼交错冲路怎么办 床的位置在五鬼上怎么办 被甩了很痛苦怎么办 和对象想分手了怎么办 对象想跟你啪啪怎么办 相亲对象好像不太想理我怎么办 想跟对象分手了怎么办 异地恋分手后该怎么办 面膜敷了一晚上怎么办 梦见被刺猬咬了怎么办