在上一篇,我們介紹了假物件Mock、Stub。用起來雖然方便,也解決了原本因為相依無法測試的問題。但每次要一這樣建mock或stub也太辛苦了,這時候我們就會用mock的框架來讓我們更方便的做到模擬物件的行為。
Mockito 是一個Mock的框架。可以讓你用簡單的程式碼就建立一個模擬物件。用來模擬物件回傳值或驗證模擬物件的行為。
在buide.gradle 的dependencies加上mockito
dependencies {
...
testImplementation "org.mockito:mockito-core:2.8.9"
}
在雨傘計算價錢的範例。我們建了一個StubWeather來回傳預期的天氣
class StubWeather :IWeather{
//建立屬性,讓外部可設定假的天氣要回傳晴天或雨天
var fakeIsSunny = false
override fun isSunny(): Boolean {
//回傳設定的假天氣
return fakeIsSunny
}
}
而使用Mockito的話,我們在寫測試時只需要這樣寫
1.使用mock() 建立模擬物件
2.使用when thenReturn 模擬回傳值。
@Test
fun totalPrice_sunnyDay(){
val umbrella = Umbrella()
//1. mock() 建立模擬物件
val weather = mock(IWeather::class.java)
//2. 模擬回傳值
`when`(weather.isSunny()).thenReturn(true)
val actual = umbrella.totalPrice(weather, 3,100)
val expected = 270
Assert.assertEquals(expected, actual)
}
是不是很簡單,不需要再寫StubWeather,輕易的達到讓weather.isSunny()回傳我們想要的結果
再來看上一篇的下單insertOrder發mail的範例,
我們寫了一個用來模擬發送Email的Mock。
class MockEmailUtil :IEmailUtil{
// receiveEmail 用來記錄由sendCustomer傳進來的Email
var receiveEmail:String? = null
override fun sendCustomer(email: String) {
receiveEmail = email
}
}
測試程式:
1.產生模擬物件:mock(IEmailUtil::class.java)
2.使用verify驗證互動
@Test
fun insertOrderWithMockito() {
val order = Order()
val mockEmailUtil = mock(IEmailUtil::class.java)
val userEmail = "someMail@gmail.com"
order.insertOrder(userEmail, 1, 200, mockEmailUtil)
//驗證是否有呼叫sendCustomer,並傳入正確的userEmail
verify(mockEmailUtil).sendCustomer(userEmail)
}
以上我們用了Mockito來達到建立Mock、Stub的模擬物件,是不是很方便。
你可以透過標示@Mock
的annotations,並在@Before裡使用MockitoAnnotations.initMocks
來建立Mock,
class OrderTest {
@Mock
lateinit var mockEmailUt:IEmailUtil
@Before
fun setup()
{
MockitoAnnotations.initMocks(this)
}
}
//驗證呼叫1次
verify(mockEmailUtil, times(1)).sendCustomer(userEmail)
//驗證不能呼叫此方法
verify(mockEmailUtil, never()).sendCustomer(userEmail)
//驗證最少呼叫1次
verify(mockEmailUtil, atLeast(1)).sendCustomer(userEmail)
//驗證最多呼叫1次
verify(mockEmailUtil, atMost(1)).sendCustomer(userEmail)
如果你不在乎方法傳入的參數,可以使用any(),表示傳入任何參數皆可
verify(mockEmailUtil).sendCustomer(any())
Mockito 還可以模擬 interface的callBack、RxJava等等,但這就等到介紹Android的Unit Test時再來說明了。
範例下載:
https://github.com/evanchen76/TDD_MockitoSample
小技巧:
單元測試也是可以設定中斷點,執行Debug來方便除錯。
出版書:
Android TDD 測試驅動開發:從 UnitTest、TDD 到 DevOps 實踐