常规的单元测试只需要引入springboot-test包,其会带入junit,mockito-core,spring-test
<!-- unit test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
单元测试class如下,如果不需要起spring环境的话可以不要@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静态方法,需要额外引入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>
单元测试class的注解替换为:
@RunWith(PowerMockRunner.class) // 告诉JUnit使用PowerMockRunner进行测试
@PrepareForTest({FaccAppConfig.class}) // 所有需要测试的类列在此处,适用于模拟final类或有final, private, static, native方法的类
@PowerMockIgnore({"javax.*.*", "com.sun.*", "org.xml.*", "org.apache.*"}) //为了解决使用powermock后,提示classloader错误
如果需要配合springboot来起spring环境,注解替换为:
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class) //RunWith依然是PowerMock,那这里Delegate委托给spring
@PowerMockIgnore({"javax.*.*", "com.sun.*", "org.xml.*", "org.apache.*"})
@PrepareForTest({FaccAppConfig.class})
@SpringBootTest
于是可以用PowerMockito来mock静态方法,when表达式依然用的Mockito的api:
PowerMockito.mockStatic(FaccAppConfig.class);
Mockito.when(FaccAppConfig.getProperty(Mockito.anyString())).thenReturn("aaabbbccc");
启动@Test测试方法时报错,因为PowerMockito版本错误造成,从1.7.4升级到2.0.0即可
运行测试方法时,因为该方法不需要spring环境所以直接执行完成,但顺带启动的spring报错:
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)
错误里提到hessian2在META-INF下的配置文件serializers,文件配置的实现类和Serializer接口对应不上。就是说SPI机制没对应上,在启动过程中debug关键代码:
发现Serializer接口被PowerMock的JavassistMockClassLoader加载,实现类被标准的AppClassLoader加载,所以无法对应上。
想起来需要排除PowerMock尽量不让加载公共类,在@PowerMockIgnore添上hessian的路径"com.caucho.*"即可。