@Injectable 與 @Mocked的不同
import mockit.Injectable;
import mockit.Mocked;
import org.junit.Assert;
import org.junit.Test;import java.util.Locale;//@Mocked 與@Injectable的不同
public class MockedAndInjectable {@Testpublic void testMocked(@Mocked Locale locale){//靜態方法不起作用了,返回了nullAssert.assertTrue(Locale.getDefault() == null);//非靜態方法(返回類型為string)也不起作用,返回了nullAssert.assertTrue(locale.getCountry() == null);//自己new一個,也同樣如此,方法都被mock了Locale chinaLocale = new Locale("zh","CN");Assert.assertTrue(chinaLocale.getCountry() == null);}@Testpublic void testInjectable(@Injectable Locale locale){//靜態方法不mockAssert.assertTrue(Locale.getDefault() != null);//非靜態方法(返回類型為string)也不起作用了,返回null,但僅僅限于locale這個對象Assert.assertTrue(locale.getCountry() == null);//自己new一個,并不受影響Locale chinaLocale = new Locale("zh","CN");Assert.assertTrue(chinaLocale.getCountry().equals("CN"));}
}
- @Injectable 也是告訴 JMockit生成一個Mocked對象,但@Injectable只是針對其修飾的實例,而@Mocked是針對其修飾類的所有實例。
- 此外,@Injectable對類的靜態方法,構造函數沒有影響。因為它只影響某一個實例嘛!
@Tested & @Injectable 兩個好基友,通常搭配使用
為便于演示,我們以電商網站下訂單的場景為例:在買家下訂單時,電商網站后臺程序需要校驗買家的身份(是否合法,例如是否在黑名單中),若下訂單沒有問題還要發郵件給買家。 相信下面的代碼,你一定能看明白 。
// 郵件服務類,用于發郵件
public interface MailService {/*** 發送郵件* @param userId 郵件接受人id* @param content 郵件內容* @return 發送成功了,就返回true,否則返回false*/public boolean sendMail(long userId, String content);
}
// 用戶身份校驗
public interface UserCheckService {/*** 校驗某個用戶是否是合法用戶* * @param userId 用戶ID* @return 合法的就返回true,否則返回false */public boolean check(long userId);
}//訂單服務類 ,用于下訂單
import javax.annotation.Resource;public class OrderService {//郵件服務類,用于向某用戶發郵件MailService mailService;@ResourceUserCheckService userCheckService;//構造函數public OrderService(MailService mailService){this.mailService = mailService;}/** 下訂單* @param buyerId 買家ID* @param itemId 商品ID* @return 返回下訂單是否成功* */public boolean submitOrder(long buyerId, long itemid){//先校驗用戶身份if(!userCheckService.check(buyerId)){//用戶身份不合法return false;}/*下單邏輯代碼省略。。。。下單完成后,給買家發郵件* */if (!this.mailService.sendMail(buyerId, "下單成功")){//郵件發送失敗return false;}return true;}
}
假設現在我們需要測試OrderService類的submitOrder方法,可是OrderService依賴MailService,UserCheckService類,在測試過程中,我們并不想真正連結郵件服務器,也不想連結校驗用戶身份的服務器校驗用戶身份,怎么辦呢?
此時@Tested與@Injectable就排上用場了!請看下面的測試程序:
import mockit.Expectations;
import mockit.Injectable;
import mockit.Tested;
import org.junit.Test;//@Tested 與@injectable搭配使用
public class TestedAndInjectable {//@Tested 修飾的類,表示是我們要測試對象,在這里表示,我想測試訂單服務類。JMockit也會幫我們實例化這個測試對象@TestedOrderService orderService;long testUserId = 1234561; //測試用戶idlong testItemId = 4567891; //測試商品id//測試注入方式@Testpublic void testSubmitOrder(@Injectable MailService mailService,@Injectable UserCheckService userCheckService){new Expectations(){{//當向testUserId發郵件時,假設都發成功了mailService.sendMail(testUserId,anyString);result = true;//當檢驗testUserId的身份時,假設該用戶都是合法的userCheckService.check(testUserId);result = true;}};//JMockit 幫我們實例化了mailService了,并通過OrderService的構造函數,注入到OrderService對象中//JMockit 幫我們實例化了userCheckService了,并通過OrderService的屬性,注入到OrderService對象中Assert.assertTrue(orderService.submitOrder(testUserId, testItemId));}
}
@Tested & @Injectable功能總結
@Injectable 也表示一個Mocked對象,相比@Mocked,只不過只影響類的一個實例。而@Mocked默認是影響類的所有實例。@Tested表示被測試對象。如果該對象沒有賦值,JMockit會去實例化它。
@Tested的構造函數有參數,則JMockit通過在測試屬性&測試參數中查找@Injectable修飾的Mocked對象注入@Tested對象的構造函數來實例化,不然,則用無參構造函數來實例化。除了構造函數的注入,JMockit還會通過屬性查找的方式,把@Injectable對象注入到@Tested對象中。
注入的匹配規則:先類型,再名稱(構造函數參數名,類的屬性名)。若找到多個可以注入的@Injectable,則選擇最優先定義的@Injectable對象。當然,我們的測試程序要盡量避免這種情況出現。因為給哪個測試屬性/測試參數加@Injectable,是人為控制的。
什么測試場景,我們要使用@Tested & @Injectable
顯然,當我們需要手工管理被測試類的依賴時,就需要用到@Tested & @Injectable。
兩者搭配起來用,JMockit就能幫我們輕松搞定被測試類及其依賴注入細節。
總結
以上是生活随笔為你收集整理的(四)JMockit 的API:@Injectable 与 @Mocked的不同--基础篇的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。