Spring Boot中採用Mockito來mock所測試的類的依賴(避免加載spring bean,避免啓動服務器)

 

最近試用了一下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,直接一下就跑完了測試。

相關文章
相關標籤/搜索