1 Mockito簡介
1.1 Mockito是什么
Mockito是一個簡單的流行的Mock框架。它允許你創建和配置mock對象。使用Mockito可以明顯的簡化對外部依賴的測試類的開發。一般使用 Mockito 需要執行下面三步:
模擬並替換測試代碼中外部依賴;
執行測試代碼;
驗證測試代碼是否被正確的執行。
1.2 Mock是什么
Mock測試就是在測試過程中,對某些不容易構造或者不容易獲取的對象,用一個虛擬的Mock對象來創建以便測試的測試方法。
Mock最大的功能是幫你把單元測試的耦合分解開,如果你的代碼對另一個類或者接口有依賴,它能夠幫你模擬這些依賴,並幫你驗證所調用的依賴的行為。
2 Mockito在Spring框架中的使用
2.1 依賴包
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>
2.21
.
0
</version>
<scope>test</scope>
</dependency>
|
Mockito在Spring可以通過配置文件和注解的方式使用
2.2 通過xml配置文件使用Mockito
Mockito創建方式有兩種:mock,spy。mock為一個interface提供一個虛擬的實現,spy為object加一個動態代理,實現部分方法的虛擬化,但是需要賦予一個instance。
Mockito提供了factory的方法用來創建mock和spy。
假設構造系統中有serviceA,serviceB,serviceC,其中serviceA依賴serviceB依賴serviceC。serviceC是最基本的。現在需要對其中serviceA進行測試,但其serviceC需要依賴於外部環境,而這個環境需要復雜而且不穩定的數據庫。這時需要mock或spy掉serviceC。
注:無論是spring框架還是spring boot框架,如果集成了MyBatis,因Mybatis中Mapper基於動態代理實現,則其對應的mapper接口只能基於xml文件配置方式注入mock或spy。
具體解釋參考:https://sq.163yun.com/blog/article/169561874192850944
第一步:在配置文件中注入mock:
<bean id=
"serviceC"
class
=
"org.mockito.Mockito"
factory-method=
"mock"
>
<constructor-arg value=
"com.x.y.x.ServiceC"
></constructor-arg>
</bean>
|
或注入spy
<bean id=
"serviceCInst"
class
=
"serviceCInstance"
>
</bean>
<bean id=
"serviceC"
class
=
"org.mockito.Mockito"
factory-method=
"spy"
>
<constructor-arg ref=
"serviceCInst"
></constructor-arg>
</bean>
|
spy需要獲得一個實例。
第二步:
在測試用例中@Resource或@Autowired引入serviceC。
2.3 通過注解使用Mockito
以代碼舉例
@Component
public
class
OrderCreate {
@Resource
private
OrderHelper orderHelper;
public
void
create() {
System.out.println(getAmt());
System.out.println(orderHelper.resolve());
}
public
int
getAmt() {
return
10
;
}
}
|
@Component
public
class
OrderHelper {
public
String
resolve() {
return
"resolve order"
;
}
}
|
測試類:
public
class
MockSpringTest {
@InjectMocks
private
OrderCreate orderCreate;
@Mock
private
OrderHelper orderHelper;
// 此mock將被注入到orderCreate
@Before
public
void
initMocks() throws Exception {
MockitoAnnotations.initMocks(
this
);
}
@Test
public
void
create() {
System.out.println(
"start mock..."
);
when(orderHelper.resolve()).thenReturn(
"null"
);
orderCreate.create();
}
}
|
運行結果:
start mock...
10
null
|
mock() / @Mock:創建一個mock;
spy() / @Spy:創建一個spy,提供了一種對真實對象操作的方法;
@InjectMocks:創建一個實例。被@Mock(或@Spy)注解創建的mock將被注入到用該實例中。注意: @InjectMocks標注的屬性不能使用接口。
3 Mockito在Spring boot 框架中的使用
3.1 Spring Boot自帶測試模塊
Spring boot自身提供很多有用的工具類和注解用於測試應用,主要分兩個模塊:spring-boot-test包含核心組件,spring-boot-test-autoconfigure為測試提供自動配置。開發者只需要引用spring-boot-starter-test即可。它提供的測試模塊中包含了Mockito。
Spring boot使用@MockBean和@SpyBean來定義Mockito的mock和spy。SpringBoot提供的@MockBean注解,用於為Applicatio nContext中的bean定義一個mock,你可以使用該注解添加新beans,或替換已存在的bean定義。該注解可直接用於測試類,也可用於測試類的字段,或用於@Configuration注解的類和字段。當用於字段時,創建mock的實例也會被注入。Mock beans每次調用完測試方法后會自動重置。
以代碼舉例:
@Component
public
class
MethodTest {
public
String
One(boolean flag){
System.err.println(
"coming........."
);
String
d = Two(flag);
Three();
System.err.println(
"result data is "
+d);
return
d;
}
public
String
Two(boolean flag){
System.err.println(
"coming.........two"
);
if
(flag){
throw
new
IllegalAccessError();
}
return
"two"
;
}
public
void
Three(){
System.err.println(
"coming.........three"
);
}
}
|
測試類 @SpyBean
@RunWith(SpringRunner.
class
)
@SpringBootTest(classes = DemoApplication.
class
)
public
class
SpyTest{
@SpyBean
private
MethodTest spyTest;
@Test
public
void
test3(){
when(spyTest.Two(
false
)).thenReturn(
"test"
);
System.err.println(spyTest.One(
false
));
}
}
|
運行結果:
coming.........two
coming.........
coming.........three
result data
is
test
test
|
測試類 @MockBean
@RunWith(SpringRunner.
class
)
@SpringBootTest(classes = DemoApplication.
class
)
public
class
MockTest{
@MockBean
private
MethodTest mockTest;
@Test
public
void
test3(){
when(mockTest.One(
false
)).thenReturn(
"test"
);
System.err.println(mockTest.One(
false
));
}
}
|
運行結果:
test
|
3.2 Spring Boot使用原生Mockito
使用方式見第2部分。
4 總結
為了統一springBoot和spring項目對Mockito的配置方式,同時解決框架中Mybaties之Mapper動態代理的mock場景,建議統一使用xml文件配置的方式。
