在Mockito中有Mock及Spy物件,分別可以用@Mock
或@Spy
來注入,但兩者差異如下。
Mock物件從頭到尾都是假的物件,當呼叫mock的方法時其實並不會做任何事,如果方法有返回值,呼叫後僅回傳null。
Spy物件幾乎同等於真的物件,當呼叫spy的方法時會呼叫真正的原方法,也會返回原方法執行後應返回的值。
觀察下面範例就可以看出Mock與Spy的區別了。
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {
@Mock
private List mockList;
@Spy
private List spyList = new ArrayList();
@Test
public void testMockList() {
// mock物件是假的, 所以呼叫方法時其實並不會做任何事
mockList.add("test"); // 並沒有真的把"test"字串加入mockList,
assertNull(mockList.get(0)); // 如果原方法有返回值, 則mock物件的方法僅返回null
}
@Test
public void testSpyList() {
// spy物件會呼叫真正的原方法
spyList.add("test"); // 真的把"test"加入spyList
assertEquals("test", spyList.get(0)); // spy物件的方法會返回值
}
@Test
public void testMockWithStub() {
String expected = "Mock 100";
// stub mock物件的get(100)方法
when(mockList.get(100)).thenReturn(expected);
assertEquals(expected, mockList.get(100));
}
@Test
public void testSpyWithStub() {
String expected = "Spy 100";
// stub spy物件的get(100)方法
// spy物件使用doReturn()來stub方法的返回值
doReturn(expected).when(spyList).get(100);
assertEquals(expected, spyList.get(100));
}
}
此時可能又會想,那spy物件和真的物件有什麼差別? 幹嘛不用真的物件就好了。因為真的物件並無法stub其方法,也無法追蹤其行為,所以要改用Spy物件來達成。
在test中常可以看到stub或stubbing,其意思是模擬原方法的行為,例如原方法執行結果返回值為"100",我們可以用stub將原方法的返回值改為"99"。所以在上面無論是stub mock或stub spy的方法,我們可以stub ArrayList.get(100)方法來模擬(自訂)返回的值。
會用stub的時機通常都是單元測試時,被測試方法中呼叫了依賴物件的方法,所以要利用stub來模擬(或偽造)依賴物件方法的行為(及返回值),而不是真的去執行依賴方法的邏輯。只有在整合測試時才會去真的呼叫依賴物件的方法。
參考:
沒有留言:
張貼留言