转载-spring的单元测试-学习中

作者原地址:http://yangblog.iteye.com/blog/964369

今天对着spring的文档看了spring-test这节,现在赶紧记下来,有错误之处还请指出。

 

   spring可以基于junit3.8、junit4.4、testNG的环境,但是注意基于junit4.4和testNG要在java1.4(包括1.4)以上的版本。 

 

    首先环境(一):spring2.5.4、junit3.8、java1.6、eclipse

 

   使用junit3.8有两种测试的方法,两种测试方法分别extends不同的类,我们一个一个来。

 

 第一种方法A:

    A方法要求测试的类继承org.springframework.test包中类,我们先来看看这个包的类的继承关系:

    AbstractSpringContextTests 

                    |

    AbstractSingleSpringContextTests

                    |

    AbstractDependencyInjectionSpringContextTests

                    |

    AbstractTransactionalSpringContextTests

                    |

    AbstractTransactionalDataSourceSpringContextTests

 

   最上面的是父类,接着第二个继承第一个以此类推。

   好了我们看看 AbstractSpringContextTests

 

Java代码 复制代码  收藏代码
  1. /**  
  2.  * Map of context keys returned by subclasses of this class, to Spring  
  3.  * contexts. This needs to be static, as JUnit tests are destroyed and  
  4.  * recreated between running individual test methods.  
  5.  */  
  6. private static Map contextKeyToContextMap = new HashMap();   
  7.   
  8.   
  9. /**  
  10.  * Default constructor for AbstractSpringContextTests.  
  11.  */  
  12. public AbstractSpringContextTests() {   
  13. }   
  14.   
  15. /**  
  16.  * Constructor for AbstractSpringContextTests with a JUnit name.  
  17.  */  
  18. public AbstractSpringContextTests(String name) {   
  19.     super(name);   
  20. }  
	/**
	 * Map of context keys returned by subclasses of this class, to Spring
	 * contexts. This needs to be static, as JUnit tests are destroyed and
	 * recreated between running individual test methods.
	 */
	private static Map contextKeyToContextMap = new HashMap();


	/**
	 * Default constructor for AbstractSpringContextTests.
	 */
	public AbstractSpringContextTests() {
	}

	/**
	 * Constructor for AbstractSpringContextTests with a JUnit name.
	 */
	public AbstractSpringContextTests(String name) {
		super(name);
	}
Java代码 复制代码  收藏代码
  1. /**  
  2.      * Load a new ApplicationContext for the given key.  
  3.      * <p>  
  4.      * To be implemented by subclasses.  
  5.      *  
  6.      * @param key the context key  
  7.      * @return the corresponding ApplicationContext instance (new)  
  8.      */  
  9.     protected abstract ConfigurableApplicationContext loadContext(Object key) throws Exception;  
/**
	 * Load a new ApplicationContext for the given key.
	 * <p>
	 * To be implemented by subclasses.
	 *
	 * @param key the context key
	 * @return the corresponding ApplicationContext instance (new)
	 */
	protected abstract ConfigurableApplicationContext loadContext(Object key) throws Exception;

 

   注意看这个static Map contextKeyToContextMap 这个是用来存放context的缓存区,作用稍后在说,

   看下面的这个抽象方法,它的作用是用来loadContext,这方法的实现在它子类AbstractSingleSpringContextTests

   中。看AbstractSingleSpringContextTests中的实现:

 

 

Java代码 复制代码  收藏代码
  1.       /**  
  2.      * <p>  
  3.      * This implementation assumes a key of type String array and loads a  
  4.      * context from the given locations.  
  5.      * </p>  
  6.      * <p>  
  7.      * If you override {@link #contextKey()}, you will typically have to  
  8.      * override this method as well, being able to handle the key type that  
  9.      * <code>contextKey()</code> returns.  
  10.      * </p>  
  11.      *  
  12.      * @see #getConfigLocations()  
  13.      */  
  14.     protected ConfigurableApplicationContext loadContext(Object key) throws Exception {   
  15.         return loadContextLocations((String[]) key);   
  16.     }   
  17.   
  18. protected ConfigurableApplicationContext loadContextLocations(String[] locations) throws Exception {   
  19.         ++this.loadCount;   
  20.         if (this.logger.isInfoEnabled()) {   
  21.             this.logger.info("Loading context for locations: " + StringUtils.arrayToCommaDelimitedString(locations));   
  22.         }   
  23.         return createApplicationContext(locations);   
  24.     }   
  25.   
  26. protected ConfigurableApplicationContext createApplicationContext(final String[] locations) {   
  27.         GenericApplicationContext context = new GenericApplicationContext();   
  28.         customizeBeanFactory(context.getDefaultListableBeanFactory());   
  29.         createBeanDefinitionReader(context).loadBeanDefinitions(locations);   
  30.         context.refresh();   
  31.         return context;   
  32.     }  
      /**
	 * <p>
	 * This implementation assumes a key of type String array and loads a
	 * context from the given locations.
	 * </p>
	 * <p>
	 * If you override {@link #contextKey()}, you will typically have to
	 * override this method as well, being able to handle the key type that
	 * <code>contextKey()</code> returns.
	 * </p>
	 *
	 * @see #getConfigLocations()
	 */
	protected ConfigurableApplicationContext loadContext(Object key) throws Exception {
		return loadContextLocations((String[]) key);
	}

protected ConfigurableApplicationContext loadContextLocations(String[] locations) throws Exception {
		++this.loadCount;
		if (this.logger.isInfoEnabled()) {
			this.logger.info("Loading context for locations: " + StringUtils.arrayToCommaDelimitedString(locations));
		}
		return createApplicationContext(locations);
	}

protected ConfigurableApplicationContext createApplicationContext(final String[] locations) {
		GenericApplicationContext context = new GenericApplicationContext();
		customizeBeanFactory(context.getDefaultListableBeanFactory());
		createBeanDefinitionReader(context).loadBeanDefinitions(locations);
		context.refresh();
		return context;
	}

 

 可以看到这个方法的实现了加载配置文件的作用,那我们怎么将我们的配置文件给AbstractSingleSpringContextTests

让它加载呢,AbstractSingleSpringContextTests有一个让我们测试类继承的方法String[] getConfigLocations()

 

Java代码 复制代码  收藏代码
  1. protected String[] getConfigLocations() {   
  2.         String[] paths = getConfigPaths();   
  3.         String[] locations = new String[paths.length];   
  4.         for (int i = 0; i < paths.length; i++) {   
  5.             String path = paths[i];   
  6.             if (path.startsWith("/")) {   
  7.                 locations[i] = ResourceUtils.CLASSPATH_URL_PREFIX + path;   
  8.             }   
  9.             else {   
  10.                 locations[i] = ResourceUtils.CLASSPATH_URL_PREFIX +   
  11.                         StringUtils.cleanPath(ClassUtils.classPackageAsResourcePath(getClass()) + "/" + path);   
  12.             }   
  13.         }   
  14.         return locations;   
  15.     }  
protected String[] getConfigLocations() {
		String[] paths = getConfigPaths();
		String[] locations = new String[paths.length];
		for (int i = 0; i < paths.length; i++) {
			String path = paths[i];
			if (path.startsWith("/")) {
				locations[i] = ResourceUtils.CLASSPATH_URL_PREFIX + path;
			}
			else {
				locations[i] = ResourceUtils.CLASSPATH_URL_PREFIX +
						StringUtils.cleanPath(ClassUtils.classPackageAsResourcePath(getClass()) + "/" + path);
			}
		}
		return locations;
	}

 在上面所说的loadContext的方法中会调用getConfigLocations()获得配置文件的位置,所以我们在我们测试的类中重写这个方法,这样就覆盖了这个方法。所以我们的测试类应该这样写

 

Java代码 复制代码  收藏代码
  1. public class TeacherDao2Test extends AbstractSingleSpringContextTests{   
  2.     protected String entryYear = "2010";   
  3.     protected Long gradeId = 1L;   
  4.     protected Long classId = 1L;   
  5.     protected Long subjectId = 1L;   
  6.     protected Long markId = 1L;   
  7.     protected Date toDate = new Date();   
  8.     protected Date fromDate;   
  9.        
  10.     protected ApplicationContext app;   
  11.        
  12. //  @Resource   
  13.     private GenericManager<AdjustedRateStandard, Long> adjustedRateStandardManager;   
  14.        
  15.     protected TeacherDao2 teacherDao2;   
  16.        
  17.     @Override  
  18.     protected String[] getConfigLocations() {   
  19.         return new String[] {"classpath:applicationContext-resources.xml",   
  20.                 "classpath:WEB-INF/applicationContext.xml",   
  21.         "classpath:applicationContext-dao.xml"};   
  22.     }   
  23.        
  24.     public void testGetQualityReviewResultArrayByDate() throws Exception {   
  25.            
  26.          GenericManager<AdjustedRateStandard, Long> adjustedRateStandardManager =  (GenericManager<AdjustedRateStandard, Long>) this.getApplicationContext().getBean("adjustedRateStandardManager");   
  27.             
  28.          List<AdjustedRateStandard> a = adjustedRateStandardManager.getAll();   
  29.          for(AdjustedRateStandard ar : a) {   
  30.              System.out.println(ar.getId());   
  31.              System.out.println(ar.getRate());   
  32.              System.out.println(ar.getDescription());   
  33.          }   
  34.          System.out.println("--------------");   
  35.         /* a = adjustedRateDao.getAll();  
  36.          for(AdjustedRate ar : a) {  
  37.              System.out.println(ar.getAreaRate());  
  38.              System.out.println(ar.getSubject().getName());  
  39.          }*/  
  40.             
  41.     }   
  42.   
  43.     public void testa() {   
  44.         /*System.out.println();  
  45.         Double x = 2.0;  
  46.         Double y = 3.0;  
  47.         Double z = 1.2;  
  48.         BigDecimal xb = new BigDecimal(String.valueOf(x));  
  49.         BigDecimal yb = new BigDecimal(String.valueOf(y));  
  50.         BigDecimal zb = new BigDecimal(String.valueOf(z));  
  51.         System.out.println(x*y*z);  
  52.         System.out.println(xb.multiply(zb).multiply(yb));  
  53.         double d = xb.multiply(zb).multiply(yb).doubleValue();  
  54.         System.out.println(d);*/  
  55.         int[] a = {3,5,9,7,4,13,15,0,2,20};     
  56.         boolean[] b = new boolean[21];     
  57.              
  58.         for(int i=0;i<a.length;i++) {     
  59.           b[a[i]] = true;     
  60.         }     
  61.              
  62.         for(int i=0;i<b.length;i++) {     
  63.           if(b[i]) {     
  64.             System.out.print(i+",");     
  65.           }     
  66.              
  67.         }     
  68.     }   
  69. }  
public class TeacherDao2Test extends AbstractSingleSpringContextTests{
	protected String entryYear = "2010";
	protected Long gradeId = 1L;
	protected Long classId = 1L;
	protected Long subjectId = 1L;
	protected Long markId = 1L;
	protected Date toDate = new Date();
	protected Date fromDate;
	
	protected ApplicationContext app;
	
//	@Resource
	private GenericManager<AdjustedRateStandard, Long> adjustedRateStandardManager;
	
	protected TeacherDao2 teacherDao2;
	
	@Override
	protected String[] getConfigLocations() {
		return new String[] {"classpath:applicationContext-resources.xml",
				"classpath:WEB-INF/applicationContext.xml",
		"classpath:applicationContext-dao.xml"};
	}
	
	public void testGetQualityReviewResultArrayByDate() throws Exception {
		
		 GenericManager<AdjustedRateStandard, Long> adjustedRateStandardManager =  (GenericManager<AdjustedRateStandard, Long>) this.getApplicationContext().getBean("adjustedRateStandardManager");
		 
		 List<AdjustedRateStandard> a = adjustedRateStandardManager.getAll();
		 for(AdjustedRateStandard ar : a) {
			 System.out.println(ar.getId());
			 System.out.println(ar.getRate());
			 System.out.println(ar.getDescription());
		 }
		 System.out.println("--------------");
		/* a = adjustedRateDao.getAll();
		 for(AdjustedRate ar : a) {
			 System.out.println(ar.getAreaRate());
			 System.out.println(ar.getSubject().getName());
		 }*/
		 
	}

	public void testa() {
		/*System.out.println();
		Double x = 2.0;
		Double y = 3.0;
		Double z = 1.2;
		BigDecimal xb = new BigDecimal(String.valueOf(x));
		BigDecimal yb = new BigDecimal(String.valueOf(y));
		BigDecimal zb = new BigDecimal(String.valueOf(z));
		System.out.println(x*y*z);
		System.out.println(xb.multiply(zb).multiply(yb));
		double d = xb.multiply(zb).multiply(yb).doubleValue();
		System.out.println(d);*/
		int[] a = {3,5,9,7,4,13,15,0,2,20};  
		boolean[] b = new boolean[21];  
		  
		for(int i=0;i<a.length;i++) {  
		  b[a[i]] = true;  
		}  
		  
		for(int i=0;i<b.length;i++) {  
		  if(b[i]) {  
		    System.out.print(i+",");  
		  }  
		  
		}  
	}
}

这样的话测试类体通过getApplicationContext()就可以获得一个AplicationContext的对象,这个对象可以直接用getbean方法获得spring的容器中的对象了。

 

在AbstractSingleSpringContextTests类中只是简单的加载了容器,当使用AbstractDependencyInjectionSpringContextTests类(及其子类)载入你的应用上下文时, 它们可以通过Setter注入选择性配置你的测试类实例。你需要做的仅仅是定义实例变量和相应的setter方法。 AbstractDependencyInjectionSpringContextTests将在getConfigLocations()方法定义的配置文件集中自动查找相应对象,注意它使用的是按类型自动装配,因此如果你有多个bean定义是相同的类型,就不能在这些bean中使用这种方法。 这种情况下,你可以使用继承的applicationContext实例变量并实现显式的查找(比如), 调用applicationContext.getBean("id")方法。

如果你不希望在测试案例中使用依赖注入,只要不声明任何public setter方法就可以简单实现。 作为替代的,你可以扩展AbstractSpringContextTests - 在org.springframework.test 包中的JUnit 3.8集成测试支持类层次的根 - 它仅仅包含了一些载入Spring上下文的简单方法,而且不在测试fixture中使用依赖注入。

 

AbstractTransactionalSpringContextTests类 依赖于应用上下文中定义的PlatformTransactionManager bean。 名字是无关紧要的,因为使用了按类型自动装配,通常你会扩展其子类AbstractTransactionalDataSourceSpringContextTests。 这个类也需要在应用上下文中有一个DataSource bean定义(同样可以是任意名称)。 它创建一个JdbcTemplate实例变量,可以用来方便的查询和删除选定表的内容( 请记住默认情况下事务将被回滚,因而这样做是安全的)。

 

最后说说context缓存的问题,在每个测试的方法被执行的之前都会去加载一次配置文件,所以在spring第一次加载成功以后会将加载的文件名字为key,加载的得到的context为vlaue存在 contextKeyToContextMap ,这样下载在加载的时候就会先去 contextKeyToContextMap 找看有没有对应的key有的话就直接获得context。在一些少见的会“污染”应用上下文的案例中需要重新载入—— 例如,改变一个bean定义或应用对象的状态—— Spring的测试支持提供了在执行下一个测试前让测试fixture重新载入配置并重建应用上下文的机制。方法就是使用AbstractSingleSpringContextTests类中的 setDirty()方法来让测试fixture在执行下一个测试案例时重新载 AbstractAnnotationAwareTransactionalTests类,这个方法就是将contextKeyToContextMap 里的对应的记录给remove掉。

 

第二种方法B:

  我们也可以使用我们的测试类继承AbstractJUnit38SpringContextTests这个类,这是使用Spring TestContext Framework

 

 框架的核心包括TestContextTestContextManager类以及TestExecutionListener接口。 每次测试都会创建TestContextManagerTestContextManager管理了一个TestContext, 它负责持有当前测试的上下文。TestContextManager还负责在测试执行过程中更新TestContext的状态并代 理到TestExecutionListener, 它用来监测测试实际的执行(如提供依赖注入、管理事务等等)。其实也就是在TestContextManager有一个TestExecutionListener的list,在每次执行测试方法前后是时候都会遍历这个list并执行对应的prepareTestInstance和beforeTestMethod和afterTestMethod方法。

  • TestContext:封装测试执行的上下文,与当前使用的测试框架无关。

  • TestContextManagerSpring TestContext Framework的主入口点, 负责管理单独的TestContext并在定义好的执行点上向所有注册的TestExecutionListener发出事件通知: 测试实例的准备,先于特定的测试框架的前置方法,迟于后置方法

  • TestExecutionListener:定义了一个监听器API与TestContextManager发布的测试执行事件进行交互, 而该监听器就是注册到这个TestContextManager上的。

    Spring提供了TestExecutionListener的三个实现, 他们都是使用默认值进行配置的(通过@TestExecutionListeners注解): DependencyInjectionTestExecutionListenerDirtiesContextTestExecutionListenerTransactionalTestExecutionListener, 他们对测试实例提供了依赖注入支持,处理@DirtiesContext注解,并分别使用默认的回滚语义对测试提供事务支持。

 好了,直接上例子:

 

Java代码 复制代码  收藏代码
  1. @ContextConfiguration(locations = {"classpath:applicationContext-resources.xml",   
  2.                         "classpath:WEB-INF/applicationContext.xml",   
  3.                         "classpath:applicationContext-dao.xml"})   
  4. public class TeacherDao2Test extends AbstractJUnit38SpringContextTests {   
  5.     protected String entryYear = "2010";   
  6.     protected Long gradeId = 1L;   
  7.     protected Long classId = 1L;   
  8.     protected Long subjectId = 1L;   
  9.     protected Long markId = 1L;   
  10.     protected Date toDate = new Date();   
  11.     protected Date fromDate;   
  12.        
  13.     protected ApplicationContext app;   
  14.        
  15.     @Resource  
  16.     private GenericManager<AdjustedRateStandard, Long> adjustedRateStandardManager;   
  17.        
  18.     protected TeacherDao2 teacherDao2;   
  19.        
  20.     public void testGetQualityReviewResultArrayByDate() throws Exception {   
  21.            
  22. //       GenericManager<AdjustedRateStandard, Long> adjustedRateStandardManager =  (GenericManager<AdjustedRateStandard, Long>) this.getApplicationContext().getBean("adjustedRateStandardManager");   
  23.             
  24.         Assert.assertNotNull("not null", adjustedRateStandardManager);   
  25.          List<AdjustedRateStandard> a = adjustedRateStandardManager.getAll();   
  26.          for(AdjustedRateStandard ar : a) {   
  27.              System.out.println(ar.getId());   
  28.              System.out.println(ar.getRate());   
  29.              System.out.println(ar.getDescription());   
  30.          }   
  31.          System.out.println("--------------");   
  32.         /* a = adjustedRateDao.getAll();  
  33.          for(AdjustedRate ar : a) {  
  34.              System.out.println(ar.getAreaRate());  
  35.              System.out.println(ar.getSubject().getName());  
  36.          }*/  
  37.             
  38.     }   
  39.   
  40.     public void testa() {   
  41.         /*System.out.println();  
  42.         Double x = 2.0;  
  43.         Double y = 3.0;  
  44.         Double z = 1.2;  
  45.         BigDecimal xb = new BigDecimal(String.valueOf(x));  
  46.         BigDecimal yb = new BigDecimal(String.valueOf(y));  
  47.         BigDecimal zb = new BigDecimal(String.valueOf(z));  
  48.         System.out.println(x*y*z);  
  49.         System.out.println(xb.multiply(zb).multiply(yb));  
  50.         double d = xb.multiply(zb).multiply(yb).doubleValue();  
  51.         System.out.println(d);*/  
  52.         int[] a = {3,5,9,7,4,13,15,0,2,20};     
  53.         boolean[] b = new boolean[21];     
  54.              
  55.         for(int i=0;i<a.length;i++) {     
  56.           b[a[i]] = true;     
  57.         }     
  58.              
  59.         for(int i=0;i<b.length;i++) {     
  60.           if(b[i]) {     
  61.             System.out.print(i+",");     
  62.           }     
  63.              
  64.         }     
  65.     }   
  66. }  
@ContextConfiguration(locations = {"classpath:applicationContext-resources.xml",
						"classpath:WEB-INF/applicationContext.xml",
						"classpath:applicationContext-dao.xml"})
public class TeacherDao2Test extends AbstractJUnit38SpringContextTests {
	protected String entryYear = "2010";
	protected Long gradeId = 1L;
	protected Long classId = 1L;
	protected Long subjectId = 1L;
	protected Long markId = 1L;
	protected Date toDate = new Date();
	protected Date fromDate;
	
	protected ApplicationContext app;
	
	@Resource
	private GenericManager<AdjustedRateStandard, Long> adjustedRateStandardManager;
	
	protected TeacherDao2 teacherDao2;
	
	public void testGetQualityReviewResultArrayByDate() throws Exception {
		
//		 GenericManager<AdjustedRateStandard, Long> adjustedRateStandardManager =  (GenericManager<AdjustedRateStandard, Long>) this.getApplicationContext().getBean("adjustedRateStandardManager");
		 
		Assert.assertNotNull("not null", adjustedRateStandardManager);
		 List<AdjustedRateStandard> a = adjustedRateStandardManager.getAll();
		 for(AdjustedRateStandard ar : a) {
			 System.out.println(ar.getId());
			 System.out.println(ar.getRate());
			 System.out.println(ar.getDescription());
		 }
		 System.out.println("--------------");
		/* a = adjustedRateDao.getAll();
		 for(AdjustedRate ar : a) {
			 System.out.println(ar.getAreaRate());
			 System.out.println(ar.getSubject().getName());
		 }*/
		 
	}

	public void testa() {
		/*System.out.println();
		Double x = 2.0;
		Double y = 3.0;
		Double z = 1.2;
		BigDecimal xb = new BigDecimal(String.valueOf(x));
		BigDecimal yb = new BigDecimal(String.valueOf(y));
		BigDecimal zb = new BigDecimal(String.valueOf(z));
		System.out.println(x*y*z);
		System.out.println(xb.multiply(zb).multiply(yb));
		double d = xb.multiply(zb).multiply(yb).doubleValue();
		System.out.println(d);*/
		int[] a = {3,5,9,7,4,13,15,0,2,20};  
		boolean[] b = new boolean[21];  
		  
		for(int i=0;i<a.length;i++) {  
		  b[a[i]] = true;  
		}  
		  
		for(int i=0;i<b.length;i++) {  
		  if(b[i]) {  
		    System.out.print(i+",");  
		  }  
		  
		}  
	}
}

 

注意,这次我使用了注解@Resource来让spring来自己帮我进行注入,在前面一种方法使用@Resource不行,当然也可以AbstractJUnit38SpringContextTests 的protected ApplicationContext applicationContext来自己在spring中取得。

注意在类的定义处使用@ContextConfiguration注解来把配置文件的位子传递给测试类,@ContextConfiguration总共有3个配置的属性,其他两个是boolean类型inheritLocations以表明是否继承父类的locations和loader表示使用自己的context加载器。

 

这种方法上下文缓存的处理和第一种方法一样。但是与上面不同的是使用@DirtiesContext 这个注解来表示重新加载,使用@DirtiesContext 注解的前提是在TestExecutionListeners中加入DirtiesContextTestExecutionListener,而我们的AbstractJUnit38SpringContextTests 中已经设置了DirtiesContextTestExecutionListener,看:

Java代码 复制代码  收藏代码
  1. @TestExecutionListeners({DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class})   
  2. public abstract class AbstractJUnit38SpringContextTests extends TestCase implements ApplicationContextAware {   
  3.   
  4.     private static int disabledTestCount = 0;   
  5.   
  6.   
  7.     /**  
  8.      * Return the number of tests disabled in this environment.  
  9.      */  
  10.     public static int getDisabledTestCount() {   
  11.         return disabledTestCount;   
  12.     }   
  13.  ...   
  14. }  
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class})
public abstract class AbstractJUnit38SpringContextTests extends TestCase implements ApplicationContextAware {

	private static int disabledTestCount = 0;


	/**
	 * Return the number of tests disabled in this environment.
	 */
	public static int getDisabledTestCount() {
		return disabledTestCount;
	}
 ...
}

 事务管理:

  对事务的支持可以通过在TestExecutionListeners加入TransactionalTestExecutionListener,同时在类或方法上加上@Transactional就可以支持事务了,在对AbstractJUnit38SpringContextTests类进行扩展了事务和SimpleJdbcTemplate的子类AbstractTransactionalJUnit38SpringContextTests.class是这样配置的。

Java代码 复制代码  收藏代码
  1. @TestExecutionListeners({TransactionalTestExecutionListener.class})   
  2. @Transactional  
  3. public abstract class AbstractTransactionalJUnit38SpringContextTests extends AbstractJUnit38SpringContextTests {   
  4.   
  5.     /**  
  6.      * The SimpleJdbcTemplate that this base class manages, available to subclasses.  
  7.      */  
  8.     protected SimpleJdbcTemplate simpleJdbcTemplate;   
  9.   
  10.     private String sqlScriptEncoding;   
  11.   
  12.   
  13.     /**  
  14.      * Constructs a new AbstractTransactionalJUnit38SpringContextTests instance.  
  15.      */  
  16.     public AbstractTransactionalJUnit38SpringContextTests() {   
  17.         super();   
  18.     }   
  19. }  
@TestExecutionListeners({TransactionalTestExecutionListener.class})
@Transactional
public abstract class AbstractTransactionalJUnit38SpringContextTests extends AbstractJUnit38SpringContextTests {

	/**
	 * The SimpleJdbcTemplate that this base class manages, available to subclasses.
	 */
	protected SimpleJdbcTemplate simpleJdbcTemplate;

	private String sqlScriptEncoding;


	/**
	 * Constructs a new AbstractTransactionalJUnit38SpringContextTests instance.
	 */
	public AbstractTransactionalJUnit38SpringContextTests() {
		super();
	}
}

 所以我们可以使测试类继承这个类AbstractTransactionalJUnit38SpringContextTests

 

下面环境改变: spring2.5.4、junit4.4、java1.6、eclipse

  同样的使用了Spring TestContext Framework,Spring TestContext Framework通过一个可定制的运行器提供了与JUnit 4.4的完全集成。 通过使用@Runwith(SpringJUnit4ClassRunner.class)来注解测试类,开发者可以实现标准的JUnit 4.4单元和集成测试, 同时还能获得TestContext框架的好处,上例子

 

 

 

 

Java代码 复制代码  收藏代码
  1. @RunWith(SpringJUnit4ClassRunner.class)   
  2. @TestExecutionListeners({DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class})   
  3. public abstract class AbstractJUnit4SpringContextTests implements ApplicationContextAware {   
  4.   
  5.     /**  
  6.      * Logger available to subclasses.  
  7.      */  
  8.     protected final Log logger = LogFactory.getLog(getClass());   
  9.   
  10.     /**  
  11.      * The {@link ApplicationContext} that was injected into this test instance  
  12.      * via {@link #setApplicationContext(ApplicationContext)}.  
  13.      */  
  14.     protected ApplicationContext applicationContext;   
  15.   
  16.   
  17.     /**  
  18.      * Set the {@link ApplicationContext} to be used by this test instance,  
  19.      * provided via {@link ApplicationContextAware} semantics.  
  20.      */  
  21.     public final void setApplicationContext(final ApplicationContext applicationContext) {   
  22.         this.applicationContext = applicationContext;   
  23.     }   
  24.   
  25. }  
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class})
public abstract class AbstractJUnit4SpringContextTests implements ApplicationContextAware {

	/**
	 * Logger available to subclasses.
	 */
	protected final Log logger = LogFactory.getLog(getClass());

	/**
	 * The {@link ApplicationContext} that was injected into this test instance
	 * via {@link #setApplicationContext(ApplicationContext)}.
	 */
	protected ApplicationContext applicationContext;


	/**
	 * Set the {@link ApplicationContext} to be used by this test instance,
	 * provided via {@link ApplicationContextAware} semantics.
	 */
	public final void setApplicationContext(final ApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
	}

}

 

 

 还有对事务和简单数据库访问的AbstractTransactionalJUnit4SpringContextTests

Java代码 复制代码  收藏代码
  1. @TestExecutionListeners({TransactionalTestExecutionListener.class})   
  2. @Transactional  
  3. public abstract class AbstractTransactionalJUnit4SpringContextTests extends AbstractJUnit4SpringContextTests {   
  4.   
  5.     /**  
  6.      * The SimpleJdbcTemplate that this base class manages, available to subclasses.  
  7.      */  
  8.     protected SimpleJdbcTemplate simpleJdbcTemplate;   
  9.   
  10.     private String sqlScriptEncoding;   
  11.   
  12.   
  13.     /**  
  14.      * Set the DataSource, typically provided via Dependency Injection.  
  15.      */  
  16.     @Autowired  
  17.     public void setDataSource(DataSource dataSource) {   
  18.         this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);   
  19.     }   
  20.   
  21.     /**  
  22.      * Specify the encoding for SQL scripts, if different from the platform encoding.  
  23.      * @see #executeSqlScript  
  24.      */  
  25.     public void setSqlScriptEncoding(String sqlScriptEncoding) {   
  26.         this.sqlScriptEncoding = sqlScriptEncoding;   
  27.     }   
  28.   
  29.   
  30.     /**  
  31.      * Count the rows in the given table.  
  32.      * @param tableName table name to count rows in  
  33.      * @return the number of rows in the table  
  34.      */  
  35.     protected int countRowsInTable(String tableName) {   
  36.         return SimpleJdbcTestUtils.countRowsInTable(this.simpleJdbcTemplate, tableName);   
  37.     }   
  38.   
  39.     /**  
  40.      * Convenience method for deleting all rows from the specified tables.  
  41.      * Use with caution outside of a transaction!  
  42.      * @param names the names of the tables from which to delete  
  43.      * @return the total number of rows deleted from all specified tables  
  44.      */  
  45.     protected int deleteFromTables(String... names) {   
  46.         return SimpleJdbcTestUtils.deleteFromTables(this.simpleJdbcTemplate, names);   
  47.     }   
  48.   
  49.     /**  
  50.      * Execute the given SQL script. Use with caution outside of a transaction!  
  51.      * <p>The script will normally be loaded by classpath. There should be one statement  
  52.      * per line. Any semicolons will be removed. <b>Do not use this method to execute  
  53.      * DDL if you expect rollback.</b>  
  54.      * @param sqlResourcePath the Spring resource path for the SQL script  
  55.      * @param continueOnError whether or not to continue without throwing an  
  56.      * exception in the event of an error  
  57.      * @throws DataAccessException if there is an error executing a statement  
  58.      * and continueOnError was <code>false</code>  
  59.      */  
  60.     protected void executeSqlScript(String sqlResourcePath, boolean continueOnError)   
  61.             throws DataAccessException {   
  62.   
  63.         Resource resource = this.applicationContext.getResource(sqlResourcePath);   
  64.         SimpleJdbcTestUtils.executeSqlScript(   
  65.                 this.simpleJdbcTemplate, new EncodedResource(resource, this.sqlScriptEncoding), continueOnError);   
  66.     }   
  67.   
  68. }  
@TestExecutionListeners({TransactionalTestExecutionListener.class})
@Transactional
public abstract class AbstractTransactionalJUnit4SpringContextTests extends AbstractJUnit4SpringContextTests {

	/**
	 * The SimpleJdbcTemplate that this base class manages, available to subclasses.
	 */
	protected SimpleJdbcTemplate simpleJdbcTemplate;

	private String sqlScriptEncoding;


	/**
	 * Set the DataSource, typically provided via Dependency Injection.
	 */
	@Autowired
	public void setDataSource(DataSource dataSource) {
		this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
	}

	/**
	 * Specify the encoding for SQL scripts, if different from the platform encoding.
	 * @see #executeSqlScript
	 */
	public void setSqlScriptEncoding(String sqlScriptEncoding) {
		this.sqlScriptEncoding = sqlScriptEncoding;
	}


	/**
	 * Count the rows in the given table.
	 * @param tableName table name to count rows in
	 * @return the number of rows in the table
	 */
	protected int countRowsInTable(String tableName) {
		return SimpleJdbcTestUtils.countRowsInTable(this.simpleJdbcTemplate, tableName);
	}

	/**
	 * Convenience method for deleting all rows from the specified tables.
	 * Use with caution outside of a transaction!
	 * @param names the names of the tables from which to delete
	 * @return the total number of rows deleted from all specified tables
	 */
	protected int deleteFromTables(String... names) {
		return SimpleJdbcTestUtils.deleteFromTables(this.simpleJdbcTemplate, names);
	}

	/**
	 * Execute the given SQL script. Use with caution outside of a transaction!
	 * <p>The script will normally be loaded by classpath. There should be one statement
	 * per line. Any semicolons will be removed. <b>Do not use this method to execute
	 * DDL if you expect rollback.</b>
	 * @param sqlResourcePath the Spring resource path for the SQL script
	 * @param continueOnError whether or not to continue without throwing an
	 * exception in the event of an error
	 * @throws DataAccessException if there is an error executing a statement
	 * and continueOnError was <code>false</code>
	 */
	protected void executeSqlScript(String sqlResourcePath, boolean continueOnError)
			throws DataAccessException {

		Resource resource = this.applicationContext.getResource(sqlResourcePath);
		SimpleJdbcTestUtils.executeSqlScript(
				this.simpleJdbcTemplate, new EncodedResource(resource, this.sqlScriptEncoding), continueOnError);
	}

}

 ok写完了,其中对spring的事务测试没有进行研究,改天补上。

补上事务:

  主要是针对使用Spring TestContext Framework的事务测试。

  前面已经提到,要使用事务,必须在TestExecutionListeners中加入TransactionalTestExecutionListener,

也就是在类名上使用注解@TestExecutionListeners({TransactionalTestExecutionListener.class})

(注意要是类没有使用@TestExecutionListeners注解或者@TestExecutionListeners为空包括所有父类,

那么spring会使用默认的Listener,也就是 DependencyInjectionTestExecutionListener

DirtiesContextTestExecutionListenerTransactionalTestExecutionListener),

但这还不够,还必须使用@Transactiona注解标明那个要使用事务,@Transactiona放在类名上时该类所有方法都会使用事务,

也可以放在测试的方法上,这样这个测试的方法就使用事务,要是想那个方法不使用事务可以使用注解@NoTransactiona;

最后因为spring需要一个transactionManager来进行管理,

所以我们需在配置文件中加入 transactionManager的一个bean

当然也可以通过在类名上加上@TransactionConfiguration(transactionManager="txMgr", defaultRollback=true)这样决定使用那个transactionManager。不加的话就使用bean id为ransactionManager的。

 

这是spring配置:

 

Xml代码 复制代码  收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  3.        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"  
  4.        default-lazy-init="true">  
  5.   
  6.     <!-- Hibernate SessionFactory -->  
  7.     <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">  
  8.         <property name="dataSource" ref="dataSource"/>  
  9.         <property name="configLocation" value="classpath:hibernate.cfg.xml"/>  
  10.         <property name="hibernateProperties">  
  11.             <value>  
  12.                 hibernate.dialect=${hibernate.dialect}   
  13.                 hibernate.query.substitutions=true 'Y', false 'N'   
  14.                 hibernate.cache.use_second_level_cache=true  
  15.                 hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider   
  16.             </value>  
  17.             <!-- Turn batching off for better error messages under PostgreSQL -->  
  18.             <!-- hibernate.jdbc.batch_size=0 -->  
  19.         </property>  
  20.     </bean>  
  21.   
  22.     <!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->  
  23.     <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
  24.         <property name="sessionFactory" ref="sessionFactory"/>  
  25.     </bean>  
  26. <bean id="adjustedRateStandardDao" class="org.appfuse.dao.hibernate.GenericDaoHibernate">  
  27.         <constructor-arg value="com.waigi.integratedreport.model.AdjustedRateStandard"/>  
  28.         <property name="sessionFactory" ref="sessionFactory"/>  
  29.     </bean>  
  30.        
  31.     <bean id="adjustedRateStandardManager" class="org.appfuse.service.impl.GenericManagerImpl">  
  32.         <constructor-arg ref="adjustedRateStandardDao" />  
  33.     </bean>  
  34. </beans>  
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"
       default-lazy-init="true">

    <!-- Hibernate SessionFactory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:hibernate.cfg.xml"/>
        <property name="hibernateProperties">
            <value>
                hibernate.dialect=${hibernate.dialect}
                hibernate.query.substitutions=true 'Y', false 'N'
                hibernate.cache.use_second_level_cache=true
                hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
            </value>
            <!-- Turn batching off for better error messages under PostgreSQL -->
            <!-- hibernate.jdbc.batch_size=0 -->
        </property>
    </bean>

    <!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
<bean id="adjustedRateStandardDao" class="org.appfuse.dao.hibernate.GenericDaoHibernate">
		<constructor-arg value="com.waigi.integratedreport.model.AdjustedRateStandard"/>
		<property name="sessionFactory" ref="sessionFactory"/>
	</bean>
	
	<bean id="adjustedRateStandardManager" class="org.appfuse.service.impl.GenericManagerImpl">
    	<constructor-arg ref="adjustedRateStandardDao" />
    </bean>
</beans>

 

 测试类:

 

Java代码 复制代码  收藏代码
  1. package com.waigi.integratedreport.dao;   
  2.   
  3.   
  4. import java.util.Calendar;   
  5. import java.util.Date;   
  6. import java.util.List;   
  7.   
  8. import javax.annotation.Resource;   
  9.   
  10. import org.appfuse.service.GenericManager;   
  11. import org.junit.Assert;   
  12. import org.junit.Before;   
  13. import org.junit.Test;   
  14. import org.junit.runner.RunWith;   
  15. import org.springframework.context.ApplicationContext;   
  16. import org.springframework.test.annotation.NotTransactional;   
  17. import org.springframework.test.annotation.Rollback;   
  18. import org.springframework.test.context.ContextConfiguration;   
  19. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;   
  20. import org.springframework.transaction.annotation.Transactional;   
  21.   
  22. import com.waigi.integratedreport.model.AdjustedRateStandard;   
  23.   
  24. @RunWith(SpringJUnit4ClassRunner.class)   
  25. @ContextConfiguration(locations = {"classpath:applicationContext-resources.xml",   
  26.                         "classpath:WEB-INF/applicationContext.xml",   
  27.                         "classpath:applicationContext-dao.xml"})   
  28. @Transactional  
  29. public class TeacherDao2Test {   
  30.     protected String entryYear = "2010";   
  31.     protected Long gradeId = 1L;   
  32.     protected Long classId = 1L;   
  33.     protected Long subjectId = 1L;   
  34.     protected Long markId = 1L;   
  35.     protected Date toDate = new Date();   
  36.     protected Date fromDate;   
  37.        
  38.     protected ApplicationContext app;   
  39.        
  40.     @Resource  
  41.     private GenericManager<AdjustedRateStandard, Long> adjustedRateStandardManager;   
  42.        
  43.     protected TeacherDao2 teacherDao2;   
  44.        
  45.     @Before  
  46.     public void init() {   
  47.         Calendar c = Calendar.getInstance();   
  48.         System.out.println("init");   
  49.         c.clear();   
  50.         c.set(201021);   
  51.         fromDate = c.getTime();   
  52.            
  53.     }   
  54.        
  55.     @Test  
  56.     @NotTransactional  
  57.     public void testGetQualityReviewResultArrayByDate() throws Exception {   
  58.            
  59. //       GenericManager<AdjustedRateStandard, Long> adjustedRateStandardManager =  (GenericManager<AdjustedRateStandard, Long>) this.getApplicationContext().getBean("adjustedRateStandardManager");   
  60.         Assert.assertNotNull("not null", adjustedRateStandardManager);   
  61.          List<AdjustedRateStandard> a = adjustedRateStandardManager.getAll();   
  62.          for(AdjustedRateStandard ar : a) {   
  63.              System.out.println(ar.getId());   
  64.              System.out.println(ar.getRate());   
  65.              System.out.println(ar.getDescription());   
  66.          }   
  67.          System.out.println("--------------");   
  68.         /* a = adjustedRateDao.getAll();  
  69.          for(AdjustedRate ar : a) {  
  70.              System.out.println(ar.getAreaRate());  
  71.              System.out.println(ar.getSubject().getName());  
  72.          }*/  
  73.             
  74.     }   
  75.        
  76.     @Test  
  77.     @Rollback  
  78.     public void testSave() {   
  79.         AdjustedRateStandard ars = adjustedRateStandardManager.get(1L);   
  80.         ars.setDescription("第一名");   
  81.         adjustedRateStandardManager.save(ars);   
  82.         Assert.assertEquals("!=", ars, adjustedRateStandardManager.get(1L));   
  83.         System.out.println(adjustedRateStandardManager.get(1L).getDescription());   
  84.            
  85.     }   
  86.   
  87. }  
package com.waigi.integratedreport.dao;


import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import org.appfuse.service.GenericManager;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.ApplicationContext;
import org.springframework.test.annotation.NotTransactional;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

import com.waigi.integratedreport.model.AdjustedRateStandard;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext-resources.xml",
						"classpath:WEB-INF/applicationContext.xml",
						"classpath:applicationContext-dao.xml"})
@Transactional
public class TeacherDao2Test {
	protected String entryYear = "2010";
	protected Long gradeId = 1L;
	protected Long classId = 1L;
	protected Long subjectId = 1L;
	protected Long markId = 1L;
	protected Date toDate = new Date();
	protected Date fromDate;
	
	protected ApplicationContext app;
	
	@Resource
	private GenericManager<AdjustedRateStandard, Long> adjustedRateStandardManager;
	
	protected TeacherDao2 teacherDao2;
	
	@Before
	public void init() {
		Calendar c = Calendar.getInstance();
		System.out.println("init");
		c.clear();
		c.set(2010, 2, 1);
		fromDate = c.getTime();
		
	}
	
	@Test
	@NotTransactional
	public void testGetQualityReviewResultArrayByDate() throws Exception {
		
//		 GenericManager<AdjustedRateStandard, Long> adjustedRateStandardManager =  (GenericManager<AdjustedRateStandard, Long>) this.getApplicationContext().getBean("adjustedRateStandardManager");
		Assert.assertNotNull("not null", adjustedRateStandardManager);
		 List<AdjustedRateStandard> a = adjustedRateStandardManager.getAll();
		 for(AdjustedRateStandard ar : a) {
			 System.out.println(ar.getId());
			 System.out.println(ar.getRate());
			 System.out.println(ar.getDescription());
		 }
		 System.out.println("--------------");
		/* a = adjustedRateDao.getAll();
		 for(AdjustedRate ar : a) {
			 System.out.println(ar.getAreaRate());
			 System.out.println(ar.getSubject().getName());
		 }*/
		 
	}
	
	@Test
	@Rollback
	public void testSave() {
		AdjustedRateStandard ars = adjustedRateStandardManager.get(1L);
		ars.setDescription("第一名");
		adjustedRateStandardManager.save(ars);
		Assert.assertEquals("!=", ars, adjustedRateStandardManager.get(1L));
		System.out.println(adjustedRateStandardManager.get(1L).getDescription());
		
	}

}

 

 从测试类可以看出,这个类的所有方法都使用了事务,除了有@NotTransactional注解的方法testGetQualityReviewResultArrayByDate,其次,加入事务的方法testsave()

可以通过注解@Rollback(value=false)来让这个事务提交而不是回滚,当然上面的实例虽然加了@Rollback但是它默认的

是true所以还是会回滚。

ol。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值