Spring集成Junit
首先說明一個問題:“測試”,測的是什麼?
其實是測“類”,測類中的屬性、方法。 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中去。
1. 導入兩個依賴:junit、spring-test
Spring提供了針對Spring做單元測試的解決方案,其依賴爲spring-test
<!--Spring-test-->
<!--注意:spring5 及以上版本要求 junit 的版本必須是 4.12 及以上-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
Maven項目中,單元測試基於junit依賴進行。spring-test方案,同樣也需要junit依賴的支持。
<!--Junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
2. 創建測試類:SpringJunitTest
在Maven項目的測試包中創建
package cn.leap.test;
/**
* Author: Feiyue
* Date: 2019/7/7 11:56
* Desc: Spring集成Junit的測試
*/
public class SpringJunitTest {
}
3. 配置測試類(註解配置)
3.1 @Runwith:替換原來的運行期
@RunWith(SpringJUnit4ClassRunner.class)//指定新的運行器,由它來創建IoC容器
public class SpringJunitTest {
}
3.2 @ContextConfiguration:指定配置文件或配置類
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(value={"classpath:applicationContext.xml"})//針對XML配置文件
@ContextConfiguration(classes = {SpringConfiguration.class})//針對配置類
//@ContextConfiguration(classes = {DataSourceConfiguration.class})//針對配置類
public class SpringJunitTest {
}
SpringConfiguration主配置類,其中導入了DataSourceConfiguration配置類
3.3 @Autowired:注入需要測試的Bean對象
@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();
}
}
4. 編寫測試方法,測試Bean對象
在測試類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;
}
}