powermock使用
- mock与spy 的区别
- 语法的区别:
Test ms = PowerMockito.mock(Test.class);
Test ms = PowerMockito.spy(new Test());
- Mock对象的区别:
mock方法生成的对象为一个空对象,即里面所有的方法均被mock了,所以在调用该对象里面的方法
时候,均不会执行该方法,仅会返回方法返回值的零值。
spy方法生成的对象是一个真实的对象,即调用该对象里面的方法时,会实际执行方法中的内容。 - 使用场景的区别:
mock方法一般比较适合用于测试类的方法需要全部被mock的情况,而spy方法适合用于测试类中方法
部分被mock的情况。
- 语法的区别:
- 公有方法mock
- 有返回值
PowerMockito.doReturn(result).when(dungeonService).enterDungeonPoint(role, dungeonType, pointId);
PowerMockito.when(forgeManager.haveForgeMaterialOnDesk(forge)).thenReturn(true);
- 无返回值
PowerMockito.doNothing().when(dungeonService).enterDungeonPoint(role, dungeonType, pointId);
- 对于任意参数均mock
PowerMockito.doReturn(result).when(dungeonService).enterDungeonPoint(Mockito.any(Role.class), Mockito.any(EnumDungeonType.class), Mockito.anyString());
- 注意:
- 方法的入参要与实际执行的入参要完全相同,否则mock失败,可以理解为此方法的mock为仅参数
为所传的参数时的方法按照预期返回对应的值,其他情况均执行方法。 - doNothing()仅仅对void返回的方法有效,其他有返回值的方法不可使用
- 方法的入参要与实际执行的入参要完全相同,否则mock失败,可以理解为此方法的mock为仅参数
- 有返回值
- 私有方法mock
- 准备:测试类继承PowerMockTestCase,测试类添加注解,注解的大括号中为被测试私有方法的类,
@PrepareForTest({UniqueService.class}) - mock:
PowerMockito.doNothing().when(uniqueService, "checkActivateUniqueCondition", role, uniqueType);
- 调用:私有方法使用反射的方法调用:boolean res = Whitebox.invokeMethod(heroService, “checkLevel”, obj, heroLevel);
- 准备:测试类继承PowerMockTestCase,测试类添加注解,注解的大括号中为被测试私有方法的类,
- 静态方法mock
- 准备:测试类继承PowerMockTestCase,测试类添加注解,注解的大括号中为被测试静态方法的类,
@PrepareForTest({UniqueService.class}),PowerMockito.mockStatic(UniqueService.class) - mock: 由于mockStatic方法的作用,该类中所有的方法均被mock,方法返回的值是对应的零值,对于有些需要指定返回值的情况可以使用:
PowerMockito.when(MasterstrokeService.class,"getShopEventWithPoint",position).thenReturn(shopEvent);
或
PowerMockito.when(MasterstrokeService.getShopEventWithPoint(position)).thenReturn(shopEvent);(推荐)
- 需要真实执行:对于有些方法不想被mock,而整个类被已经被mock的情况:
PowerMockito.doCallRealMethod().when(MasterstrokeService.class, "checkInitShop", role, eventId, pos);
(公有方法:PowerMockito.doCallRealMethod().when(forgeService).syncClientData(this.role, record);
)
PowerMockito.when(MasterstrokeService.getLineTagByPoint(startPoint, endPoint)).thenCallRealMethod();
(when中必须有返回值)
- 准备:测试类继承PowerMockTestCase,测试类添加注解,注解的大括号中为被测试静态方法的类,
- 单元测试的验证
- 验证结果与预期相同:
assertEquals(baseException.getType(), result);
- 验证方法是否被执行
PowerMockito.verifyPrivate(MasterstrokeService.class,Mockito.atLeastOnce()).invoke("methodName", param1, param2);
Mockito.verify(forgeTaskManager, Mockito.atLeastOnce()).sendTaskReward(param1, param2);
- 验证结果与预期相同:
- 测试中的其他需求
- 需要mock被mock的对象中的一个成员时:
forgeManager = PowerMockito.mock(ForgeManager.class);
forgeService = PowerMockito.mock(ForgeService.class);
Whitebox.setInternalState(forgeService, "forgeManager", forgeManager);
保证forgeService调用forgeManager的对象时是被mock的。否则可能导致mock失败,forgeService的中的forgeManager对象与实际使用
的不一致。 - 希望方法执行中某些new生成的对象为指定的对象时:
Random random = PowerMockito.spy(new Random());
PowerMockito.whenNew(Random.class).withAnyArguments().thenReturn(random);
PowerMockito.doReturn(ranData).when(random, "nextFloat");
- 需要mock被mock的对象中的一个成员时:
技术拓展
- Mockito.any()仅仅可以匹配一些对象类型,包括String类型而不能匹配基本类型,基本类型需要使用对应的Mockito方法,如int则使用Mockito.anyInt()
- mock方法时,要求要么统一使用具体的值,要么统一使用any匹配,不能部分参数是具体值,而另一部分使用mockito.any之类的匹配。
- 有这样一个需求:mock方法时,有部分的入参不关心,或者该参数构造很麻烦,而另一部分参数需要使用具体的值,那么对于不关心的使用Mockito.any之类,而对于具体值可以使用Mockito.eq(value)(value是具体的数值,如果是对象,则必须是相同的对象(即引用相同))。