使用PowerMock mock注入属性出现空指针异常如何解决
PowerMock测试时@Inject字段为空触发空指针修复
问题根因
- 手动通过
new Foo()创建被测类实例时,PowerMock不会自动将@Mock修饰的Tango mock对象注入到Foo类的私有tango字段中,调用tango.fly(bar)时tango为null,直接触发空指针。 - Golf对象没有触发异常是因为它是作为方法入参直接传入的,不属于Foo的内部注入字段,和注入逻辑无关。
- 原代码还有两个隐藏问题:
@PrepareForTest列表漏加了Bar类:要拦截new Bar()的构造逻辑,必须把调用new语句的Foo类、被实例化的Bar类都加入列表,否则whenNew逻辑不生效- 没有给
tangoBar.fly()方法打桩:普通Mock对象的int类型返回默认值0,就算注入成功,断言>0也会失败
修复方案
方案1:使用@InjectMocks自动注入(推荐)
用@InjectMocks注解修饰被测类实例,PowerMock会自动把所有同类型的@Mock对象注入到实例的对应字段中,不需要手动new实例。
修改后的完整测试代码:
@RunWith(PowerMockRunner.class) @PrepareForTest({Foo.class, Bar.class}) public class FooTest{ @Mock Golf golfMock; @Mock Tango tangoBar; // 标记被测实例,自动注入mock字段 @InjectMocks Foo fooMock; @Test public void travelTest() throws Exception { List<String> testList = Arrays.asList("a","b"); Bar barMock = new Bar(); barMock.setList(testList); // 拦截Bar无参构造 PowerMockito.whenNew(Bar.class).withNoArguments().thenReturn(barMock); // 给tango的fly方法打桩,定义符合断言的返回值 PowerMockito.when(tangoBar.fly(any(Bar.class))).thenReturn(1); Assert.assertTrue(fooMock.travel(golfMock) > 0); } }
方案2:反射手动注入(适配特殊场景)
如果有特殊场景不能用@InjectMocks,可以直接通过反射给私有字段赋值:
@Test public void travelTest() throws Exception { List<String> testList = Arrays.asList("a","b"); Bar barMock = new Bar(); barMock.setList(testList); PowerMockito.whenNew(Bar.class).withNoArguments().thenReturn(barMock); // 手动创建实例后反射注入tango字段 Foo fooMock = new Foo(); Field tangoField = Foo.class.getDeclaredField("tango"); tangoField.setAccessible(true); tangoField.set(fooMock, tangoBar); PowerMockito.when(tangoBar.fly(any(Bar.class))).thenReturn(1); Assert.assertTrue(fooMock.travel(golfMock) > 0); }
注:不需要放到@PrepareForTest里的类不要随便加,只有需要mock构造方法、静态方法、私有方法、final方法的类才需要加入该列表,普通@Mock的类不需要加,避免不必要的字节码增强引发其他问题。
内容的提问来源于stack exchange,提问作者oitathi
相关产品推荐
相关产品推荐

