首先说明一个问题:“测试”,测的是什么?
其实是测“类”,测类中的属性、方法。 Spring中统一把java类称为Bean对象
Spring中,Bean对象都是由Spring容器进行创建的。因此,Spring中对于Bean对象的测试,必须得先获取Spring容器,再从容器中取得Bean对象。所以,这两个步骤的代码,是每一个测试类都必须要写的代码。
无论是XML配置,还是注解配置,都必须要写“获取 Spring容器、从容器取Bean对象”的代码,如:
public class SpringAnnotationTest {
/**
* Spring新注解的测试
*/
@Test
public void testSpringNewAnnotation() throws Exception {
//获取Spring容器,并从容器中获取数据源
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);//必须指明主配置类的字节码文件
DataSource dataSource = (DataSource) context.getBean("dataSource");
//从数据源中获取连接
Connection connection = dataSource.getConnection();
System.out.println(connection);
//dao、service的测试
UserService userService = (UserService) context.getBean("userServiceImpl");
userService.save();
}
/**
* 原始注解测试,其中也用到了XML配置
*/
@Test
public void testSpringOriginAnnotation() {
//获取Spring容器,并从中获取Bean对象
String config = "applicationContext.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(config);
UserService service = (UserService) context.getBean("UserServiceImpl");
//调用对象中的方法
service.save();
}
}
每写一个测试都要重复“获取Spring容器、从容器中获取Bean对象”的步骤,这是需要优化的。Spring自然会提供优化的方案。
这个方案的思路是:将原始的Junit单元测试包,集成到Spring中去。
Spring提供了针对Spring做单元测试的解决方案,其依赖为spring-test
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>5.0.5.RELEASEversion>
dependency>
Maven项目中,单元测试基于junit依赖进行。spring-test方案,同样也需要junit依赖的支持。
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
在Maven项目的测试包中创建
package cn.leap.test;
/**
* Author: Feiyue
* Date: 2019/7/7 11:56
* Desc: Spring集成Junit的测试
*/
public class SpringJunitTest {
}
@RunWith(SpringJUnit4ClassRunner.class)//指定新的运行器,由它来创建IoC容器
public class SpringJunitTest {
}
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(value={"classpath:applicationContext.xml"})//针对XML配置文件
@ContextConfiguration(classes = {SpringConfiguration.class})//针对配置类
//@ContextConfiguration(classes = {DataSourceConfiguration.class})//针对配置类
public class SpringJunitTest {
}
SpringConfiguration主配置类,其中导入了DataSourceConfiguration配置类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfiguration.class})
public class SpringJunitTest {
@Autowired
private UserService userService;
}
@Autowired是按类型注入。所以,前提是Spring容器中已经有了一个UserService类型的Bean对象。
这就需要在UserService实现类中声明好一个Bean对象,而这正是要被测试的Bean对象。
@Service("userServiceImpl") //@Service 用于service层实例化Bean
public class UserServiceImpl implements UserService {
/*@Autowired
@Qualifier("userDao")*/
@Resource(name="userDaoImpl")
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void save() {
userDao.save();
}
}
在测试类SpringJunitTest中编写测试方法
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfiguration.class})//针对配置类
public class SpringJunitTest {
@Autowired
private UserService userService;
@Test
public void test01(){
userService.save();
}
}
测试方法test01(),必须要用@Test这个单元测试注解进行配置,否则是运行不了的。
这也是spring-test需要junit支持的原因所在。
(spring-test是Spring集成Junit的一种解决方案,根本还是在Junit。)
UserDaoImpl: save()............
John
com.mysql.jdbc.Driver
Service对象中又注入有Dao对象,这是在“Spring依赖注入”时就写好的测试代码。
以上的步骤,看起来并没有简化Spring中的单元测试,反而搞得更复杂了。
再来看测试类的代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfiguration.class})//针对配置类
public class SpringJunitTest {
@Autowired
private UserService userService;
@Test
public void testUserService(){
userService.save();
}
}
上面代码是进行某一个Bean对象的测试。
之前的所有步骤相当于是在搭建SpringJunit测试的环境。----------这一点非常重要
当再需要对第2个、第3个…第n个Bean对象进行测试时,测试环境已经搭建好了,直接在测试环境中(SpringJunitTest类中)注入相应的Bean对象,并写相应的测试方法即可。
这才是SpringJunit简化Spring中单元测试的理念所在。
如下,再要对DataSource对象进行测试,直接在测试环境中注入Bean对象,并进行测试即可。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfiguration.class})//针对配置类
public class SpringJunitTest {
@Autowired
private UserService userService;
@Autowired
private DataSource dataSource;
@Test
public void testUserService(){
userService.save();
}
@Test
public void testDataSource() throws SQLException {
Connection connection = dataSource.getConnection();
System.out.println(connection);
}
}
测试方法的个数,看自己的需要。
问题:
前面讲了“@Autowired是按类型注入。所以,前提是Spring容器中已经有了一个UserService类型的Bean对象。”那么,上面代码中注入的待测试对象DataSource对象,是在哪里存放到Spring容器中去的??
//步骤1:设定了主配置类
@ContextConfiguration(classes = {SpringConfiguration.class})//针对配置类
public class SpringJunitTest {
}
//步骤2:主配置类导入DataSourceConfiguration配置类
@Configuration//声明该类为Spring核心配置类
@ComponentScan("cn.leap")//指定进行组件扫描的包
@Import({DataSourceConfiguration.class})//导入其他配置类
public class SpringConfiguration {
}
//步骤3:DataSourceConfiguration配置类配置了Bean对象
@PropertySource("classpath:jdbc.properties")//加载配置文件
public class DataSourceConfiguration {
@Bean(name = "dataSource")//指示Spring将当前方法的返回值以指定名称放到Spring容器中
public DataSource getDataSource() throws Exception {
//获取连接池对象
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
//返回DataSource对象
return ds;
}
}