最近試用了一下Mockito,感受真的挺方便的。舉幾個應用實例:spring
1,須要測試的service中注入的有一個dao,而我並不須要去測試這個dao的邏輯,只須要對service進行測試。這個時候怎麼辦呢,mockito就能夠作到把這個dao給mock了,調用這個dao的方法會直接返回預設的值,不會去真正的執行dao裏的邏輯,省時省力,專一於眼前。數據庫
2,不想在單測時啓動容器,加載一堆沒有用的東西。這個時候你就能夠把你的單元測試寫成一個純junit的test類,能夠飛快的跑完測試邏輯,不用等待server加載,spring加載等亂七八糟的過程。固然這個只是一個附帶的好處,主要仍是1。ide
下面寫來一段簡單的代碼,稍做講解(項目基於spring boot,其實無所謂,只要有junit,mockito,spring依賴便可,數據庫配置什麼的也須要本身已經配好了,這裏不作說明)。函數
先來實體類:單元測試
/** * Created by zp on 2017/11/20. */ @Data @Builder @Entity @Table public class Model { private Long id; private String name; }
Lombok註解就很少解釋了。標準Bean測試
DAO:ui
/** * Created by zp on 2017/11/20. */ @Repository public class ModelDao { public Model getModel(Long id){ return Model.builder().id(id).name("model from dao ").build(); } }
最簡單的dao,實際上應該是訪問數據庫,爲了方便,這裏構建一個對象返回出去。注意name是model from dao,由這個dao得出的對象name都會是這個,mock出來的會是另外一個。this
Service:spa
/** * Created by zp on 2017/11/20. */
@Service public class ModelServiceImpl implements ModelService { @Autowired ModelDao modelDao; @Override public Model getModel(Long id) { return modelDao.getModel(id); } }
接口的實現類,ModelService就一個方法,這裏不寫了。3d
好了,基礎的service和dao,bean都有了。如今咱們要對ModelService作測試,按照傳統的方式,Tests代碼以下:
@RunWith(SpringRunner.class) @SpringBootTest public class DemoApplicationTests { @Autowired ModelService modelService; @Test public void contextLoads() { Model model = modelService.getModel(3L); System.out.println(model); Assert.assertEquals(3l,model.getId().longValue()); } }
這個會加載spring的一堆依賴,而後按照spring的注入規則,把ModelService注入進來,同時也會把ModelDao注入到ModelService中,運行一下,熟悉的畫面:
單測會順利經過:
控制檯也會打印以下輸出:
可見這個是真的走的dao的代碼邏輯,若是是真實業務代碼,那這就去讀數據庫了。
這個流程雖然也能跑,可是牽扯的東西太多,還要保證ModelDao能正確注入,運行;還要加載一堆spring/server的東西,耗時耗力。
下面就用mockito來改寫一下Tests代碼,結果以下:
public class DemoApplicationTests { @InjectMocks private ModelService modelService= new ModelServiceImpl(); @Mock private ModelDao modelDao; @Before public void setUp() { MockitoAnnotations.initMocks(this); when(modelDao.getModel(any(Long.class))) .thenReturn(Model.builder().id(1L).name("model from mock").build()); } @Test public void contextLoads() { Model model = modelService.getModel(3L); System.out.println(model); Assert.assertEquals(3l,model.getId().longValue()); } }
主要有如下幾點變化:
1,@RunWith(SpringRunner.class),@SpringBootTest這兩個註解去掉,整個Test清除了Spring Test依賴,能夠避免加載額外的東西;
2,Autowire 改爲以下:
@InjectMocks private ModelService modelService= new ModelServiceImpl();
再也不Autowire,而是InjetMocks,而且要本身new出Service對象;
3,添加Mock Dao的代碼
@Mock private ModelDao modelDao;
表示這個對象是須要Mock的
4,初始化Mockito,編寫Mock邏輯
@Before public void setUp() { MockitoAnnotations.initMocks(this); when(modelDao.getModel(any(Long.class))) .thenReturn(Model.builder().id(1L).name("model from mock").build()); }
重點在when()這個方法裏,when函數以須要mock的方法做爲參數,any表示任何輸入,thenReturn設置返回的值。
這句when的意思就是當碰到modelDao的getModel函數,傳入參數爲任何一個Long,則直接返回一個新的,本身構建的Model對象,避免執行ModelDao的真實代碼。
先看一下代碼,mock後ModelDao不管輸入任何參數,都會返回一個id爲1,name爲model from mock的Model對象,這個單測確定是跑不過的。讓咱們來驗證一下:
果真跟咱們預期的同樣,而且徹底沒有加載spring,直接一下就跑完了測試。