Springboot使用PowerMock單元測(cè)試

常規(guī)的單元測(cè)試只需要引入springboot-test包,其會(huì)帶入junit,mockito-core,spring-test

<!-- unit test -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

單元測(cè)試class如下,如果不需要起spring環(huán)境的話可以不要@SpringBootTest和@RunWith:

@SpringBootTest
@RunWith(SpringRunner.class)
public class ContractServiceTest {
    @Mock
    private IParameterService parameterService;
    @InjectMocks
    @Autowired
    private PriceServiceImpl priceService;

    @Before
    public void before() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void test1() {
        ...
    }
}

如果需要mock靜態(tài)方法,需要額外引入powerMock:

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>2.0.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>2.0.0</version>
    <scope>test</scope>
</dependency>

單元測(cè)試class的注解替換為:

@RunWith(PowerMockRunner.class) // 告訴JUnit使用PowerMockRunner進(jìn)行測(cè)試
@PrepareForTest({FaccAppConfig.class}) // 所有需要測(cè)試的類列在此處,適用于模擬final類或有final, private, static, native方法的類
@PowerMockIgnore({"javax.*.*", "com.sun.*", "org.xml.*", "org.apache.*"}) //為了解決使用powermock后,提示classloader錯(cuò)誤

如果需要配合springboot來(lái)起spring環(huán)境,注解替換為:

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class) //RunWith依然是PowerMock,那這里Delegate委托給spring
@PowerMockIgnore({"javax.*.*", "com.sun.*", "org.xml.*", "org.apache.*"})
@PrepareForTest({FaccAppConfig.class})
@SpringBootTest

于是可以用PowerMockito來(lái)mock靜態(tài)方法,when表達(dá)式依然用的Mockito的api:

PowerMockito.mockStatic(FaccAppConfig.class);
Mockito.when(FaccAppConfig.getProperty(Mockito.anyString())).thenReturn("aaabbbccc");

啟動(dòng)@Test測(cè)試方法時(shí)報(bào)錯(cuò),因?yàn)镻owerMockito版本錯(cuò)誤造成,從1.7.4升級(jí)到2.0.0即可


圖片.png

運(yùn)行測(cè)試方法時(shí),因?yàn)樵摲椒ú恍枰猻pring環(huán)境所以直接執(zhí)行完成,但順帶啟動(dòng)的spring報(bào)錯(cuò):

Caused by: com.caucho.hessian4.HessianException: jar:file:/D:/work/mavenRepository/com/focustech/serialization-hessian2/1.1.0/serialization-hessian2-1.1.0.jar!/META-INF/serialization/hessian/serializers: com.caucho.hessian4.io.RemoteSerializer is invalid because it does not implement com.caucho.hessian4.io.Serializer
at com.caucho.hessian4.io.ContextSerializerFactory.initSerializerFiles(ContextSerializerFactory.java:344)
at com.caucho.hessian4.io.ContextSerializerFactory.init(ContextSerializerFactory.java:261)
at com.caucho.hessian4.io.ContextSerializerFactory.<init>(ContextSerializerFactory.java:105)
at com.caucho.hessian4.io.ContextSerializerFactory.create(ContextSerializerFactory.java:127)
at com.caucho.hessian4.io.ContextSerializerFactory.create(ContextSerializerFactory.java:125)
at com.caucho.hessian4.io.ContextSerializerFactory.create(ContextSerializerFactory.java:125)
at com.caucho.hessian4.io.ContextSerializerFactory.create(ContextSerializerFactory.java:125)
at com.caucho.hessian4.io.SerializerFactory.<init>(SerializerFactory.java:109)
at com.caucho.hessian4.io.SerializerFactory.<init>(SerializerFactory.java:102)
at com.focus.candy.rpc.protocol.serialization.HessianSerialization.<clinit>(HessianSerialization.java:29)

錯(cuò)誤里提到hessian2在META-INF下的配置文件serializers,文件配置的實(shí)現(xiàn)類和Serializer接口對(duì)應(yīng)不上。就是說(shuō)SPI機(jī)制沒對(duì)應(yīng)上,在啟動(dòng)過(guò)程中debug關(guān)鍵代碼:


圖片.png

圖片.png

圖片.png

發(fā)現(xiàn)Serializer接口被PowerMock的JavassistMockClassLoader加載,實(shí)現(xiàn)類被標(biāo)準(zhǔn)的AppClassLoader加載,所以無(wú)法對(duì)應(yīng)上。
想起來(lái)需要排除PowerMock盡量不讓加載公共類,在@PowerMockIgnore添上hessian的路徑"com.caucho.*"即可。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容