目前应用比较普遍的java单元测试工具 junit4+Mock(Mockito、jmock、EasyMock、powermock)。为什么会选择powermock? 在做单元测试的时候,我们会发现我们要测试的方法会有很多外部依赖的对象或者一些其他服务的调用比如说(发送邮件,网络通讯,soa调用)。 而我们没法控制这些外部依赖的对象。 为了解决这个问题,我们需要用到Mock来模拟这些外部依赖的对象,从而控制它们。只关心我们自己的业务逻辑是否正确。而这时powermock就起作用了,它不仅可以mock外部的依赖,还可以mock私有方法、final方法,总之它的功能很强大。
PowerMock是一个框架,它以更强大的功能扩展了其他模拟库,例如EasyMock。 PowerMock使用自定义的类加载器和字节码操作来模拟静态方法,构造函数, 最终类和方法,私有方法,删除静态初始化程序等。通过使用自定义类加载器,无需对IDE或持续集成服务器进行任何更改,从而简化了采用过程。熟悉受支持的模拟框架的开发人员会发现PowerMock易于使用,因为整个期望API都是相同的, 无论是静态方法还是构造函数。PowerMock 旨在通过少量方法和注释扩展现有的API,以启用额外的功能。
2.0.2 org.powermock powermock-module-junit4 ${powermock.version} test org.powermock powermock-api-mockito2 ${powermock.version} test
这是一个需要被mock的类里面有私有方法、静态方法、等等下面一一来演示各个方法的mock功能。
/** * * @Date: 2020/3/31 * @Description: */ @Repository public class DemoDao { public String mockPublicMethod(String type) throws Throwable { throw new Throwable(); } public final String mockFinalMethod(String type) throws Throwable { throw new Throwable(); } public static String mockStaticMethod(String type) throws Throwable { throw new Throwable(); } } /** * @Date: 2020/3/31 11:34 * @Description: */ @Component public class DemoService extends AbstractDemo{ @Autowired private DemoDao demoDao; public String mockPublicMethod() throws Throwable { return demoDao.mockPublicMethod("demo"); } public String mockFinalMethod() throws Throwable { return demoDao.mockFinalMethod("demo"); } public String mockStaticMethod() throws Throwable { return DemoDao.mockStaticMethod("demo"); } private String callPrivateMethod(String type) { return type; } public String mockPublicMethodCallPrivateMethod(String type) throws Throwable { return callPrivateMethodThrowable(type); } private String callPrivateMethodThrowable(String type) throws Throwable { throw new Throwable(); } public String mockExtendMethod(String type) throws Throwable { return getExtendMethod(); } public static String UUID = "uuid"; }
/** * @Date: 2020/4/24 14:22 * @Description: */ @RunWith(PowerMockRunner.class) public class DemoServiceTest { @InjectMocks private DemoService demoService; @Mock private DemoDao demoDao; /** * mock 普通方法 * @throws Throwable */ @Test public void mockPublicMethod() throws Throwable { String type = UUID.randomUUID().toString(); PowerMockito.when(demoDao.mockPublicMethod(any())).thenReturn(type); String result = demoService.mockPublicMethod(); Assert.assertEquals(type, result); } }
跟普通方法是一样的,唯一的区别是需要在类上加入PrepareForTest注解
@RunWith(PowerMockRunner.class) @PrepareForTest(DemoDao.class) public class DemoServiceTest { @InjectMocks private DemoService demoService; @Mock private DemoDao demoDao; /** * mock final方法 * @throws Throwable */ @Test public void mockFinalMethod() throws Throwable { String type = UUID.randomUUID().toString(); PowerMockito.when(demoDao.mockFinalMethod(any())).thenReturn(type); String result = demoService.mockFinalMethod(); Assert.assertEquals(type, result); } }
(使用 PowerMockito.mockStatic)被mock的类也要用PrepareForTest注解修饰。
@RunWith(PowerMockRunner.class) @PrepareForTest(DemoDao.class) public class DemoServiceTest { @InjectMocks private DemoService demoService; @Mock private DemoDao demoDao; /** * mock 静态方法 * @throws Throwable */ @Test public void mockStaticMethod() throws Throwable { String type = UUID.randomUUID().toString(); PowerMockito.mockStatic(DemoDao.class); PowerMockito.when(DemoDao.mockStaticMethod(any())).thenReturn(type); String result = demoService.mockStaticMethod(); Assert.assertEquals(type, result); } }
/** * 调用私有方法 * * @throws Throwable */ @Test public void callPrivateMethod() throws Throwable { // 第一种方式 String type = UUID.randomUUID().toString(); Method method = PowerMockito.method(DemoService.class, "callPrivateMethod", String.class); String result = (String) method.invoke(demoService, type); Assert.assertEquals(type, result); //第二种方式 String result1 = Whitebox.invokeMethod(demoService, "callPrivateMethod", type); Assert.assertEquals(type, result1); }
(被mock的类也要用PrepareForTest注解修饰。)
/** * mock私有方法 * @throws Throwable */ @Test public void mockPrivateMethod() throws Throwable { String type = UUID.randomUUID().toString(); // 重点这一句 demoService = PowerMockito.spy(demoService); PowerMockito.doReturn(type).when(demoService,"callPrivateMethodThrowable",type); String result = demoService.mockPublicMethodCallPrivateMethod(type); Assert.assertEquals(type, result); }
/** * mock父类方法 * @throws Throwable */ @Test public void mockExtendMethod() throws Throwable { String type = UUID.randomUUID().toString(); // 需要mock的父类的方法 Method method = PowerMockito.method(AbstractDemo.class, "getExtendMethod"); // InvocationHandler PowerMockito.replace(method).with((proxy, method1, args) -> type); String result = demoService.mockExtendMethod(type); Assert.assertEquals(type, result); }
public DemoService() { throw new NullPointerException(); } @Test public void mockConstructorMethod() throws Throwable { PowerMockito.whenNew(DemoService.class).withNoArguments().thenReturn(demoService); }
/** * mock 字段 */ @Test public void mockFiled(){ String uuid = UUID.randomUUID().toString(); Whitebox.setInternalState(DemoService.class, "UUID",uuid); Assert.assertEquals(DemoService.UUID, uuid); } //mock私有map Field field = CoreBookingDeliveryCache.class.getDeclaredField("coreBookingDeliveryDtoMap"); FieldSetter.setField(coreBookingDeliveryCache, field, builderCoreBookingDeliveryMap());