1、spring的单元测试
(1)为什么要用spring的单元测试:
A、应用程序的入口:main方法;
B、junit中没有main方法也能执行,是因为junit中集成了一个main方法,它去判断哪些方法上有对应的@Test注解,然后执行之;
C、但是在junit中,它不会去管我们是否使用spring,所以每次进行测试都要去读取配置文件,创建对象!
(2)比如现在有一个类UserDao,我们要测试它的add方法;
UserDao.java:
package cn.melo.dao;
import org.springframework.stereotype.Component;
@Component(value = "userDao")
public class UserDao {
public void add(){
System.out.println("add........");
}
}
beans.xml中配置注解扫描:
<!--扫描注解-->
<context:component-scan base-package="cn.melo"></context:component-scan>
原始的做法(只用junit):
package cn.melo.test;
import cn.melo.dao.UserDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test1 {
@Test
public void test1(){
ApplicationContext context = new
ClassPathXmlApplicationContext("beans.xml");
UserDao userDao = context.getBean("userDao", UserDao.class);
System.out.println(userDao);
userDao.add();
}
}
测试结果:
用spring的单元测试的做法
首先导入junit相关的jar包和spring-test的jar包,然后写测试代码:
package cn.melo.test;
import cn.melo.dao.UserDao;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
//如果创建对象使用的是注解配置,那么就指定注解在哪个类上
@ContextConfiguration(classes = UserDao.class)
//如果创建对象使用的是xml配置,那么就指定xml的位置
//@ContextConfiguration(locations = "classpath:beans.xml")
public class Test {
@Autowired
private ApplicationContext context;
@org.junit.Test
public void test(){
UserDao userDao = context.getBean("userDao",UserDao.class);
System.out.println(userDao);
userDao.add();
}
}
测试结果:
可见用spring的单元测试时,只需要提供一个ApplicationContext类型的属性,再给它加上自动注入的注解,它就会在执行测试方法之前,去加载配置文件;就不用频繁的去读配置文件了,也便于测试人员测试(因为可能他们不知道如何读取spring配置文件)!
2、spring的声明式事务管理
(1)、搭建一个转账环境:
表user1:
(2)、创建service和dao类完成注入
User1.java
package cn.melo.bean;
import java.io.Serializable;
public class User1 implements Serializable {
private Integer uid;
private String uname;
private Double umoney;
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public Double getUmoney() {
return umoney;
}
public void setUmoney(Double umoney) {
this.umoney = umoney;
}
@Override
public String toString() {
return "User1{" +
"uid=" + uid +
", uname='" + uname + '\'' +
", umoney=" + umoney +
'}';
}
}
user1Dao.java:
package cn.melo.dao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
public class User1Dao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
//转钱的方法
public void giveMoney(){
//操作数据库
//先让Anthony少200元
String sql = "update user1 set umoney=umoney-? where uid=?";
jdbcTemplate.update(sql,200,1);
}
//收钱的方法
public void recieveMoney(){
//再让melo多两百元
String sql = "update user1 set umoney=umoney+? where uid=?";
jdbcTemplate.update(sql,200,2);
}
}
User1Service.java
package cn.melo.service;
import cn.melo.dao.User1Dao;
public class User1Service {
private User1Dao user1Dao;
public void setUser1Dao(User1Dao user1Dao) {
this.user1Dao = user1Dao;
}
public void transferAccounts(){
user1Dao.giveMoney();
user1Dao.recieveMoney();
}
}
beans.xml:
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--扫描注解-->
<context:component-scan base-package="cn.melo"></context:component-scan>
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///mydb?serverTimezone=GMT%2b8&characterEncoding=utf8">
</property>
<property name="username" value="root"></property>
<property name="password" value="123"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="druidDataSource"></property>
</bean>
<bean id="user1Dao" class="cn.melo.dao.User1Dao">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<bean id="user1Service" class="cn.melo.service.User1Service">
<property name="user1Dao" ref="user1Dao"></property>
</bean>
</beans>
测试代码:
Test.java
package cn.melo.test;
import cn.melo.service.User1Service;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:beans.xml")
public class Test {
@Autowired
private ApplicationContext context;
@org.junit.Test
public void testTransferAccounts(){
User1Service user1Service = context.getBean("user1Service",User1Service.class);
user1Service.transferAccounts();
}
}
测试结果
还原user1表,然后在service的两个操作之间中加入一个异常再测试;
再测试:
这是我们不希望看到的,我们希望User1Dao中的两个操作,要么都成功,要么都失败!!
所以,我们就需要事务来管理这两个操作:
配置事务(加上以下的配置):
beans.xml:
<!--配置事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="druidDataSource"></property>
</bean>
<!--配置事务增强-->
<tx:advice id="txadvice" transaction-manager="transactionManager">
<!--做事务操作-->
<tx:attributes>
<!--设置进行事务操作的方法的匹配规则-->
<!--propagation:事务的传播行为-->
<!--isolation:事务的隔离级别-->
<tx:method name="transferAccounts" propagation="REQUIRED" isolation="REPEATABLE_READ" read-only="false"/>
</tx:attributes>
</tx:advice>
<!--配置切面-->
<aop:config>
<!--切入点-->
<aop:pointcut id="pointcut1" expression="execution(* cn.melo.service.User1Service.*(..))"/>
<!--切面-->
<aop:advisor advice-ref="txadvice" pointcut-ref="pointcut1"></aop:advisor>
</aop:config>
不加异常的情况下测试,没有问题,可以成功转账;
加入异常后,出现回滚!!!
(3)用注解完成事务的配置:
分三步:
第一步:配置事务管理器:
beans.xml:
<!--配置事务管理器-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="druidDataSource"></property>
</bean>
第二步:开启事务注解:
beans.xml
<!--开启事务注解-->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
第三步,在要进行事务处理的类上加上注解:@Transactional
分别进行有无异常的测试都可以成功,表明OK!!!