Spring Test的作用
在普通測試環(huán)境下,我們在使用Spring的時候,需要手動加載Spring配置,手動從Spring容器中獲取對象,前文中的使用全是如此,這也就違背了我們使用Spring框架的意愿:自動創(chuàng)建對象,自動管理對象。我們把這種用法叫自動裝配。
Spring還有一個用處,使用@Sql注解,此注解可在測試類方法之前定義,提前或延后執(zhí)行某段sql語句,在測試中也經(jīng)常使用。
在項目中加入Spring Test
添加依賴
<!--Spring Test依賴-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.14</version>
</dependency>
Spring Test無法單獨工作,仍需配合其他測試依賴項和其他Spring依賴一起使用,可參照Mybatis一文中的依賴進行添加,亦可在原項目中直接操作。但要注意,要和其他Spring依賴項的版本保持一致,切記。
創(chuàng)建測試類
package cn.codingfire.mybatis;
public class MybatisTest {
}
此時需在測試類上添加@SpringJUnitConfig注解:
package cn.codingfire.mybatis;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
@SpringJUnitConfig(SpringConfig.class)
public class MybatisTest {
}
接著我們可以在此類中添加Spring的配置類,這樣,在此類中任何方法之前,都會先加載Spring的配置類,Spring容器中存在的類就都可以實現(xiàn)自動裝配了。我們以環(huán)境變量為例:
package cn.codingfire.mybatis;
import cn.codingfire.mybatis.config.SpringConfig;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
@SpringJUnitConfig(SpringConfig.class)
public class MybatisTest {
@Autowired
Environment env;
@Test
public void testEnvironment() {
System.out.println(env.getProperty("datasource.url"));
System.out.println(env.getProperty("datasource.driver"));
System.out.println(env.getProperty("datasource.username"));
System.out.println(env.getProperty("datasource.password"));
}
}
接著運行此測試方法,查看輸出:
已經(jīng)成功輸出了我們在properties文件中配置的信息。對比之前Mybatis中的測試方法如下:
@Test
public void loadBasicInfo() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
ConfigurableEnvironment environment = ac.getEnvironment();
System.out.println(environment.getProperty("datasource.url"));
System.out.println(environment.getProperty("datasource.driver"));
System.out.println(environment.getProperty("datasource.username"));
System.out.println(environment.getProperty("datasource.password"));
ac.close();
}
先獲取ac,再獲取environment,最后再關(guān)閉ac,簡化了太多步驟。使用Spring Test,我們只需關(guān)注測試的內(nèi)容本身,而不用去管環(huán)境的問題,效果要更好。再增刪改查時也不需要再關(guān)注開頭和結(jié)尾的那幾段代碼,這種重復性的操作被省略,也是自動裝配的精髓之一。
關(guān)于@Autowired注解,就是自動裝配的意思,我們可以嘗試著給其他的對象添加此注解:
會看到AdminMapper報一個錯,這里有個小知識點。這是因為編譯器問題導致無法識別,解決辦法是在AdminMapper的類中添加@Repository注解,回來后再看,正常來說報錯會消失,但有的人的不會消失,可在注解里添加required屬性為false:
此時,問題已經(jīng)解決了,它的意思是,能裝配上就裝,不能裝配也不強求。有意思的是,即使你不管這個報錯,方法也可正常運行,不存在任何影響。
Spring Test下的測試方法
我們以插入方法為例,做個前后對比。
未使用Spring Test的插入方法測試:
@Test
public void testInsert() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
AdminMapper adminMapper = ac.getBean(AdminMapper.class);
Admin admin = new Admin();
admin.setUsername("admin04");
admin.setPassword("123456");
adminMapper.insert(admin);
ac.close();
}
使用了Spring Test的插入方法測試 :
@Test
public void testInsert() {
Admin admin = new Admin();
admin.setUsername("admin04");
admin.setPassword("123456");
adminMapper.insert(admin);
}
前后對比明顯,自動裝配后,adminMapper由系統(tǒng)創(chuàng)建管理,可在類中直接使用,簡化了代碼。
@Sql注解
@Sql注解的作用和注意事項
Spring Test測試類中,還可以使用@Sql注解,他可以加載某些腳本.sql的腳本,可以在測試前后執(zhí)行一些給定的sql語句。它的作用是可以在測試時進行反復測試,在Mybatis中,我們在測試時,有時為了使mapper的方法運行成功,需要運行插入的方法,這就很不友好了,增加了測試的成本,比如我刪除某條數(shù)據(jù)后,表中沒有數(shù)據(jù),我要再執(zhí)行刪除操作前,必須要再插入一條數(shù)據(jù),否則會報錯,而我使用@Sql注解,就可以解決這個問題,使得每次測試不需要再關(guān)注其他的方法。
使用此注解要注意幾個問題:
@Sql注解可以添加在單獨的方法中,僅對此方法有效,也可添加在測試類上,對類中所有的方法有效。如果類和方法上都添加了相同的@Sql注解,僅方法上的生效
可方法前執(zhí)行.sql腳本,也可方法后執(zhí)行.sql腳本,通過executionPhase屬性來管理
@Sql注解可添加多個
@Sql注解怎么用
首先,我們需要先創(chuàng)建一個.sql文件,選擇file,創(chuàng)建一個truncate.sql:
在test下的resoutces文件中創(chuàng)建,在此文件中可以看到和再sql工具中一樣,是有sql提醒的。 truncate的意思是截斷,在sql中意味著清空整張表。我們知道,數(shù)據(jù)庫表中不允許插入相同的兩條數(shù)據(jù),否則就會報重復的錯誤,使用此注解,在每次插入前都清空整張表就可以頻繁測試,看代碼:
@Sql(scripts = {"classpath:truncate.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Test
public void testInsert() {
Admin admin = new Admin();
admin.setUsername("admin04");
admin.setPassword("123456");
adminMapper.insert(admin);
}
可以在插入前清空整張表,以達到頻繁插入的測試。
以刪除為例,我們想刪除的時候數(shù)據(jù)庫表中一直有數(shù)據(jù)。此時,也可以使用此注解,接下來我們來說說怎么同時使用多個.sql腳本,首先創(chuàng)建一個插入的.sql腳本:
看代碼:
@Sql(scripts = {"classpath:truncate.sql", "classpath:insert.sql"})
@Test
public void testDelete() {
adminMapper.deleteById(1L);
}
每次執(zhí)行次方法都是成功的。如果你想在方法執(zhí)行后再執(zhí)行某些sql的話,可以設(shè)置@Sql的executionPhase屬性為Sql.ExecutionPhase.AFTER_TEST_METHOD:
executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD
斷言
我們通常在測試類中使用Assertions類的靜態(tài)方法對測試結(jié)果進行預測,幫助我們發(fā)現(xiàn)代碼中可能存在的問題,一旦不符合預測的正確結(jié)果就會報錯,大大提高代碼的正確性。常用的一些斷言方法有:
assertEquals():斷言匹配(相等)
assertNotEquals():斷言不匹配(不相等)
assertTrue():斷言為“真”
assertFalse():斷言為“假”
assertNull():斷言為null
assertNotNull():斷言不為null
assertThrows():斷言拋出異常
assertDoesNotThrow():斷言不會拋出異常
其他
接下來我們挑幾個在代碼中來看使用效果。
assertEquals():
@Sql(scripts = {"classpath:truncate.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
@Test
public void testInsert() {
Admin admin = new Admin();
admin.setUsername("admin04");
admin.setPassword("123456");
int index = adminMapper.insert(admin);
System.out.println(index);
Assertions.assertEquals(1,index);
}
Assertions.assertEquals 有兩個參數(shù),第一個是expected,是期望的值,第二個是ectual,是實際的值,如果預測的不對,就會報錯,正確則沒有任何反應。
assertTrue()
還以插入為例,看代碼:
@Sql(scripts = {"classpath:truncate.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
@Test
public void testInsert() {
Admin admin = new Admin();
admin.setUsername("admin04");
admin.setPassword("123456");
int index = adminMapper.insert(admin);
System.out.println(index);
boolean isThanZero = index > 0 ? true : false;
Assertions.assertTrue(isThanZero);
}
斷言isThanZero,即影響的行數(shù)大于0,則說明插入成功,否則將報異常。
assertNull()
以根據(jù)id獲取數(shù)據(jù)為例:
@Test
public void getById() {
Admin admin = adminMapper.getById(10L);
Assertions.assertNull(admin);
}
id為10的數(shù)據(jù)表中沒有,所以語言admin為null,是正確的,符合我們的預期,不會報錯。
assertThrows()
前面我們說過重復插入數(shù)據(jù)會把哦重復插入的異常,這時就不能在插入前清空表了,我們以此為例,看代碼:
@Test
public void testInsert() {
Admin admin = new Admin();
admin.setUsername("admin04");
admin.setPassword("123456");
Assertions.assertThrows(DuplicateKeyException.class, () -> {
adminMapper.insert(admin);
});
}
正常來說,連續(xù)執(zhí)行兩次,就會拋出重復插入的異常,但是我們做了斷言后,就不會有任何輸出,反而會在第一次執(zhí)行時拋出下面這段異常:
org.opentest4j.AssertionFailedError: Expected org.springframework.dao.DuplicateKeyException to be thrown, but nothing was thrown.
意思是說,我們預測會拋出重復的異常,但是什么也沒有拋出。這是正常的,因為第一次插入成功了。
到這里,斷言就寫完了,上面列出來的每一類中的一個都給出了案例 ,照葫蘆畫瓢,對另一個取反就是另一個,相信聰明如大家已經(jīng)知道該怎么用了,不再贅述。
本站文章版權(quán)歸原作者及原出處所有 。內(nèi)容為作者個人觀點, 并不代表本站贊同其觀點和對其真實性負責,本站只提供參考并不構(gòu)成任何投資及應用建議。本站是一個個人學習交流的平臺,網(wǎng)站上部分文章為轉(zhuǎn)載,并不用于任何商業(yè)目的,我們已經(jīng)盡可能的對作者和來源進行了通告,但是能力有限或疏忽,造成漏登,請及時聯(lián)系我們,我們將根據(jù)著作權(quán)人的要求,立即更正或者刪除有關(guān)內(nèi)容。本站擁有對此聲明的最終解釋權(quán)。