当下的大部分的Java项目都是基于Spring框架的,这固然带来了很大的便利,但是也引入了一些其他的问题。例如在对Service、Component进行单元测试的时候,虽然Junit等测试框架提供了相关框架的支持,但是如果是一个有点儿历史的、封装并不是很很合理的、方法类的单一职责做的不好的项目,进行一次单元测试,框架启动耗时30秒,测试方法5ms。时间举例有些极端,但这也是目前很多项目真实面临的情况。
脱离框架的支持,直接进行单元测试,面临的第一个较大的问题就是“依赖”如何解决。Spring及Spring-boot框架解决的一个大问题就是依赖管理的问题,其提供的依赖注入和自动装配确实提供了很大的便利性,但在单元测试进行时最大的阻力就是这些依赖如何注入的问题。有框架支持的情况下可以从bean容器中拿来即用,但若是脱离了框架就需要手动进行初始化。
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import java.lang.reflect.Field;
// 指定运行器纯属个人习惯,使用默认的也可
@RunWith(MockitoJUnitRunner.class)
public class ClassATest {
private final ClassA clazzA = new ClassA();
private final ClassB clazzB = Mockito.mock(ClassB.class);
private final ClassC clazzC = Mockito.mock(ClassC.class);
@Test
public void onceTest() throws IllegalAccessException {
// 将需要的对象注入被测试对象
Field[] declaredFields = ClassA.class.getDeclaredFields();
for (Field field : declaredFields) {
field.setAccessible(true);
if (field.getName().equals("classA")) {
field.set(tradeOrderStore, orderNoUtil);
} else if (field.getName().equals("clazzB")) {
field.set(tradeOrderStore, tradeProductUtil);
}
}
//打桩、模拟
Mockito.when(clazzB.bMethod(Mockito.any())).thenReturn("MC" + new Random().nextInt(1999999999));
Mockito.when(clazzC.bMethod(Mockito.anyInt())).thenReturn(Boolean.TRUE);
// 构建测试方法的入参
TestParam tp = new TestParam();
// 为测试入参设置测试值的代码省略......
// 使用测试入参,执行测试方法
Result testResult = clazzA.aMethod(tp);
Assert.assertNotNull(testResult);
// 其他测试验证省略......
}
}
通过以上,就可以脱离框架执行进行单元测试了,此时单元测试的运行执行就大大降低了。