背景
項目使用的是springmvc+mybatis 開發;
mock包為 mockito-all;雖然也引用了powermock,但截至目前,還未使用到;如果使用到后續再補相關筆記。
mock,個人理解,有兩個場景比較常見吧。一個是在項目初期接口定義好后沒有實現邏輯階段;另一個就是針對已經有的邏輯自測階段,而又不想(或者依賴的別人接口不想關心)被別人所左右的情況。
不管那種情況,都是一個目的:降低別人對自己的干擾。
大概從兩個方面記錄單測的mock:
dapper層:
dapper層,目前是給mybatis的定義接口層;這一層主要會結合mybatis.xml 與數據庫進行交互;當開發階段沒有寫完邏輯時,那就需要先來個“假實現”,這樣不會影響團隊中其他小伙伴的工作開展嘛。
public class ReportMediaDayMapperTest { @Mock private ReportMediaDayMapper reportMediaDayMapper; // 定義了mybatis與數據庫交互時,用到的接口 @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); } @After public void tearDown() throws Exception { } @Test public void getAdvertiserAndMediaStatList() throws Exception { MediaSearchModel searchModel = new MediaSearchModel(); List<AdvertiserAndMediaStatViewModel> list = new ArrayList<>(); when(reportMediaDayMapper.getAdvertiserAndMediaStatList(searchModel)).thenReturn(list); // mock一個場景,就是當請求getAdvertiserAndMediaStatList方法時,返回值為指定的 list;
List<AdvertiserAndMediaStatViewModel> list2 = reportMediaDayMapper.getAdvertiserAndMediaStatList(searchModel);
assertTrue(list2.isEmpty()); // 斷言list2為空,因為上面就是一個實例化並沒有賦值,所以也是為空了。
}
對於DAO層,主要用到的是 @Mock的使用。那么這個注解的作用究竟是什么呢?下面會結合另外一個一起總結。
service層:
主要mock對象一般就是對DAO層的依賴,另外就是別人的Service實現類;
@RunWith(MockitoJUnitRunner.class) public class MediaServiceImplTest { @Mock private ReportMediaDayMapper mediaDayMapper; // mock 一個DAO層的接口 @InjectMocks private MediaServiceImpl mediaService; // Mock一個Service的實現類,為什么用@InjectMocks,一會兒說 @Test public void getAdvertiserAndMediaStatList() throws Exception { MediaSearchModel searchModel = new MediaSearchModel(); List<AdvertiserAndMediaStatViewModel> list = new ArrayList<>(); when(mediaDayMapper.getAdvertiserAndMediaStatList(searchModel)).thenReturn(list); list = mediaService.getAdvertiserAndMediaStatList(searchModel); assertTrue(list.isEmpty()); }
其實,對於以上兩個場景的mock,主要是圍繞着@Mock、@InjectMocks進行玩的。那么他們分別代表什么意思呢?
官方文檔上是這么描述的:
mock()
/@Mock
: create mockspy()
/@Spy
: partial mocking, real methods are invoked but still can be verified and stubbed- optionally specify how it should behave via
Answer
/ReturnValues
/MockSettings
when()
/given()
to specify how a mock should behave- If the provided answers don’t fit your needs, write one yourself extending the
Answer
interface
- optionally specify how it should behave via
@InjectMocks
: automatically inject mocks/spies fields annotated with@Spy
or@Mock -- 這句話理解意思是它會把上下文中你標記為@Spy和@Mock的對象都自動注解進去。是不是就相當於把實現類中的私有成員屬性(比如ReportMediaDayMapper的依賴
)給偷梁換柱了
verify()
: to check methods were called with given arguments
另外,就是你可能會注意到了@RunWith(MockitoJUnitRunner.class),其實也可以用另外一種方式(看↓)處理,就是初始化一些需要的東西。
@Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); } @After public void tearDown() throws Exception { }
至此,簡單的mock測試就完了。其實只是冰山一角。mockito中有很多很多很多。常用的一些@spy、@mock、@injectMocks、以及Verify、when then、doreturn ……
參考:
https://github.com/hehonghui/mockito-doc-zh
http://site.mockito.org/
http://static.javadoc.io/org.mockito/mockito-core/2.7.6/org/mockito/Mockito.html