使用mock進行單元測試
在service層,使用mock來測試程式碼。而不再使用Juint測試
JUint是java單元測試的框架,已經在Eclipse中預設的安裝。目前主流的有JUnit3和JUnit4.JUint3中,測試用例需要繼承TestCase類,JUint4中,測試用例無需繼承TestCase類,只需要使用@Test等註解。
JUint4主要通過註解的方式來識別測試方法。目前支援的主要註解有:
@BeforeClass全域性只會執行一次,而且是第一個執行。
@Before在測試方法執行之前執行
@Test測試方法
@After在測試方法執行之後允許
@AfterClass全域性只會執行一次,而且是最後一個執行
@Ignore忽略此方法
Juint3和JUint4都提供了一個Assert類。Assert類中定義了很多靜態方法來進行斷言。
Mockito與JUint不同,並不是單元測試框架。它是用於生成模擬物件或者直接點說,就是“假物件”的工具。
Mock/Stub
Mock和Stub是兩種測試程式碼功能的方法。Mock側重於對功能的模擬,Stub測重於對功能的測試重現,例如對List介面。Mock會直接對List進行模擬,而Stub會新建一個實現了List的TestList,在其中編寫測試的程式碼。
強烈建議優先選擇Mock方式,因為Mock方式下,模擬程式碼與測試程式碼放在一起,易讀性好,而且擴充套件性、靈活性都比Stub好。
比較流行的Mock
JMock
EasyMock
Mockito
powermock
其中EasyMcock和Mocking對於Java介面使用介面代理的方式來模擬。對於Java類使用繼承的方式來模擬(即會建立一個新的Class類)。Mockito支援spy方式。可以對例項進行模擬。但他們都不能對靜態方法和final類進行模擬。
Mockito是一個開源專案。Api相對於EasyMock更友好,與EasyMock不同的是,Mockito沒有錄製過程,只需要在“執行測試程式碼”之前對介面進行Stub,即設定方法的返回值或丟擲的異常。然後直接執行測試程式碼。執行期間呼叫Mock的方法,會返回預先設定的返回值或丟擲異常。最後再對測試程式碼進行驗證。
- mport static org.mockito.Mockito.*;
- //建立Mock
- List mockedList = mock(List.class);
- //使用Mock物件
- mockedList.add("one");
- mockedList.clear();
- //驗證行為
- verify(mockedList).add("one");
- verify(mockedList).clear();
首先是配置 Mock 物件,、
List mock = mock( List.class );
when( mock.get(0) ).thenReturn( 1 );
assertEquals( "預期返回1", 1, mock.get( 0 ) );
Mockito支援 迭代風格 的返回值設定,
- 第一種方式 when(i.next()).thenReturn("Hello").thenReturn("World");
- 第二種方式 when(i.next()).thenReturn("Hello", "World");
上面的例子等價於:
when(i.next()).thenReturn("Hello");
when(i.next()).thenReturn("World");
第一次呼叫i.next()將返回”Hello”,第二次的呼叫會返回”World”。
對 void 方法不返回值,所以不能 when(mock.someMethod()).thenReturn(value) 這樣的語法,可以這樣
doNothing().when(i).remove();
doThrow(Throwable) 模擬返回異常
doThrow(new RuntimeException()).when(i).remove();
迭代風格 doNothing().doThrow(new RuntimeException()).when(i).remove();,這樣,第一次呼叫remove方法什麼都不做,第二次呼叫丟擲RuntimeException異常。
(1)如何將mock的類自動注入到待測類中?在測試程式碼中,使用@Inject將service層注入,@Mock註釋Mapper。
public class AService {
}
public class AServiceTest extends Test4J{
@Inject(targets= { “ AService” })
@Mock
private AMapper aMapper;
}