一、一般邏輯的單元測試。
這裡采用的方式和資料通路層幾乎是一樣的,主要包含三步:
1. 通過@databasesetup指定測試用資料集
2. 執行被測試方法
假設要被測試的代碼方法是:
@service
@transactional(readonly = true)
public class shopserviceimpl extends baseservice implements shopservice{
private logger logger = loggerfactory.getlogger(shopserviceimpl.class);
@transactional(readonly = false)
public floor addfloor(string buildingname, int floornum, string layout) {
//如果已經存在對應的樓層資訊,則抛出已經存在的異常資訊
floor floor = floordao.findbybuildingnameandfloornum(buildingname, floornum);
if (floor != null) {
throw new onlineshopexception(exceptioncode.shop_floor_existed);
}
//如果不存在對應的商場資訊,則添加新的商場
building building = buildingdao.findbyname(buildingname);
if (building == null) {
building = new building();
building.setname(buildingname);
buildingdao.save(building);
//添加并傳回樓層資訊
floor = new floor();
floor.setbuilding(building);
floor.setfloornum(floornum);
floor.setmap(layout);
floordao.save(floor);
return floor;
其對應的接口是:
public interface shopservice {
public floor addfloor(string buildingname, int floornum, string layout);
}
這段邏輯代碼的意思十分簡單和直白,那麼要編寫的單元的測試必須要包含所有分支情況:a. 商場和樓層資訊都存在的,抛出異常 b. 商場存在,而樓層不存在, 樓層資訊都被添加的。 c. 商場和樓層都不存在,全部新增。這裡就以第一種情況為例,先準備測試資料:
<?xml version="1.0" encoding="utf-8"?>
<dataset>
<building id="1" name="new house"/>
<floor id="1" building="1" floor_num="2"/>
</dataset>
接着編寫測試用例,注意要必須得注解不能忘掉:
@runwith(springjunit4classrunner.class)
@contextconfiguration("classpath:applicationcontext-test.xml")
@transactional
@testexecutionlisteners({
dependencyinjectiontestexecutionlistener.class,
dirtiescontexttestexecutionlistener.class,
customtransactiondbunittestexecutionlistener.class,
foreignkeydisabling.class})
public class shopservicetest {
@autowired
private shopservice shopservice;
@test
@databasesetup("shop/shopservice-addfloorexistexception-dataset.xml")
public void testaddfloorexistexception(){
try {
shopservice.addfloor("new house", 2, "");
fail();
} catch(exception e){
asserttrue(e instanceof onlineshopexception);
assertequals(exceptioncode.shop_floor_existed.code(), ((onlineshopexception)e).getcode());
這個測試和資料通路層的測試看起來沒有什麼兩樣。
二、使用mock對象隔離第三方接口
軟體開發中一般都存在和第三方內建的情況,比如調用新浪的認證、百度的地圖等等。那麼在編寫測試的時候,基于效率的考慮,一般情況不會真的去調用這些遠端api(當然應該有其他測試可以及時發現第三方接口的變化),而是假定它們一直會傳回預期的結果。這個時候就需要用到mock對象,來模拟這些api産生相應的結果。
在這裡,我是用了mockito,使用十分友善。假如現在使用者登入時,需要去第三方系統驗證,那麼現在來看如何對這個場景進行測試。還是先來看被測試的方法:
private boolean validateuser(string inputname, string inputpassword) {
return thirdpartyapi.authenticate(inputname, inputpassword);
其中thirdpartyapi就是第三方用來認證的api。下面來看測試代碼:
public class userservicetest {
private userservice userservice;
private thirdpartyapi mockthirdpartyapi = mock(thirdpartyapi.class);
public void testlogin(){
//指定mock對象特定操作的傳回結果
when(mockthirdpartyapi.authenticate("jiml", "jiml")).thenreturn(true);
//通過setter用mock對象替換由spring初始化的第三方依賴
((userserviceimpl)userservice).setthirdpartyapi(mockthirdpartyapi);
boolean loginstatus = userservice.login("jiml", "jiml");
asserttrue(loginstatus);
其實服務層的測試并沒有太多的新東西,而最關鍵的問題是如何把邏輯中各個分支都能測試到,使測試真正起到為軟體品質保駕護航的作用。
最新内容請見作者的github頁:http://qaseven.github.io/