PowerMock 单元测试 常见问题

1、引入的包

powermock-module-junit4
powermock-api-mockito2
javassist
mockito-core
2、常用的方法
2.1 方法名上注解

@RunWith(PowerMockRunner.class)
@PrepareForTest(Log.class)
//  @PowerMockIgnore({"javax.management.*", "javax.script.*"})  不要忽略报错
@SuppressStaticInitializationFor({
        // 应该抑制 mock的对象静态属性和静态块的初始化
        "com.sleepycat.je.SecondaryDatabase"})

2.2 mock类

PowerMockito.mockStatic(Log.class);
// mockstaic 静态类的方法 如果你doNothing 就不需要mock,默认就是 doNothing
// PowerMockito.doNothing().when(Log.class, PowerMockito.method(Log.class, "e", Exception.class)).withArguments(Mockito.any());
// 被测试类 正常属性值,可以直接set
queryPropertiesconfig = PowerMockito.mock(QueryPropertiesconfig.class);
testOwner.queryPropertiesQconfig = queryPropertiesQconfig;

2.3 mock 私有属性 https://blog.csdn.net/github_32521685/article/details/50556243

// BrandSetParam  mock实例
MemberModifier.field(BrandSetParam.class, "brandSet").set(param, brandSet);
其他的 mock  静态私有 属性方法
PowerMockito.mockStatic(QueryUtils.class);
// Whitebox.setInternalState(QueryUtils.class, "brandsetcount", 10);
Field field = PowerMockito.field(QueryUtils.class, "brandsetcount");
field.setInt(null ,10);

2.4 模拟私有方法(private method)

MemberModifier.stub(MemberMatcher.method(PrivateObject .class, "getPrivateString")).toReturn( "Power Mock");

抑制父类的方法 和 替换父类的方法

作者:zyxing
链接:https://www.zhihu.com/question/58768289/answer/522121438
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

@RunWith(PowerMockRunner.class)
@PrepareForTest(Bar.class)
public class FooTest {
     

    @Test
    public void testBar() throws Exception {
     
        Method method = PowerMockito.method(Bar.class, "bar");
        // 抑制父类的这个方法执行
        PowerMockito.suppress(method);

        Foo foo = new Foo();
        foo.bar();
    }

    @Test
    public void testNumBar() throws Exception {
     
        Method methodFoo = PowerMockito.method(Foo.class, "numBar");
        // 替换掉父类的方法
        PowerMockito.replace(methodFoo).with(new InvocationHandler() {
     
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     
                return 1;
            }
        });

        Foo foo = new Foo();
        int numBar = foo.numBar();

        Assert.assertEquals(1, numBar);
    }    
}

2.5 测试被测对象的私有方法,使用反射

Method method = PowerMockito.method(TrafficInfoWrapperImpl.class, "getTrafficInfoEntity", HotelInfoType.class, TrafficInfoParameter.class);
TrafficInfoEntity positionInfo = (TrafficInfoEntity) method.invoke(trafficInfoWrappers, hotelInfoType, trafficInfoParameter);

2.6

3、遇见的异常

java.lang.IllegalStateException: Failed to transform class with name XXXXXX
InterfaceMethodrefInfo cannot be cast to MethodrefInfo
解决办法:

<dependency>
   <groupId>org.powermock</groupId>
   <artifactId>powermock-module-junit4</artifactId>
   <scope>test</scope>
   <exclusions>
      <exclusion>
         <artifactId>javassist</artifactId>
         <groupId>org.javassist</groupId>
      </exclusion>
   </exclusions>
</dependency>

<dependency>
   <groupId>org.javassist</groupId>
   <artifactId>javassist</artifactId>
   <version>3.22.0-GA</version>
</dependency>

参考 : http://www.javaear.com/question/31189086.html

3.2 Mock在前,new 被测试的类的实例 放在后后面,否则可能出现 new 的时候就依赖了 mock的数据,比如有 静态代码块
3.3 mock 任意值 和 特定值 混搭

// 被 mock方法
public static Integer getDefaultInt(String key,Integer defaultValue) {
     //}
// correct
PowerMockito.when(SystemInfo.getDefaultInt(Mockito.anyString(), Mockito.anyInt())).thenReturn(3); 
// correct
PowerMockito.when(SystemInfo.getDefaultInt("sort.change.day", 2)).thenReturn(3);
// incorrect 不能任意值 和 特定值 混搭
PowerMockito.when(SystemInfo.getDefaultInt(Mockito.anyString(), 2)).thenReturn(3);

对应的报错信息

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Invalid use of argument matchers!
2 matchers expected, 1 recorded:
-> at com.ctrip.hotel.search.das.mlstoreproduct.datafilter.MlstoreproductDataFilterTest.testParseDasEntity(MlstoreproductDataFilterTest.java:57)

This exception may occur if matchers are combined with raw values:
    //incorrect:
    someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
    //correct:
    someMethod(anyObject(), eq("String by matcher"));

4、InjectMocks 和 Mock

@InjectMocks:创建一个实例,简单的说是这个Mock可以调用真实代码的方法,其余用@Mock(或@Spy)注解创建的mock将被注入到用该实例中。

@Mock:对函数的调用均执行mock(即虚假函数),不执行真正部分。

@Spy:对函数的调用均执行真正部分。

Mockito中的Mock和Spy都可用于拦截那些尚未实现或不期望被真实调用的对象和方法,并为其设置自定义行为。二者的区别在于Mock不真实调用,Spy会真实调用。

    @InjectMocks
    private HotFeatureRepositoryImpl repository;

    @Mock
    private GetProvinceFilterClient<List<HotSearchKeywordStatModel>> getProvinceFilterClient;
    @Test
    public void getHotFeaturesByProvinceAsync_Invalid() {
     
        repository.getHotFeaturesByProvinceAsync(0);
    }

注意事项:
InjectMocks 被测试类如果有父类,并且会有一些静态属性初始化的话,会在@before前执行,所以可能会出现NPE等错误。

你可能感兴趣的:(单元测试,java)