如何使用PowerMockito模拟私有静态方法?

26

我试图模拟私有静态方法anotherMethod()。请参见下面的代码

public class Util {
    public static String method(){
        return anotherMethod();
    }

    private static String anotherMethod() {
        throw new RuntimeException(); // logic was replaced with exception.
    }
}

这是我的测试代码

@PrepareForTest(Util.class)
public class UtilTest extends PowerMockTestCase {

        @Test
        public void should_prevent_invoking_of_private_method_but_return_result_of_it() throws Exception {

            PowerMockito.mockStatic(Util.class);
            PowerMockito.when(Util.class, "anotherMethod").thenReturn("abc");

            String retrieved = Util.method();

            assertNotNull(retrieved);
            assertEquals(retrieved, "abc");
        }    
}

但每次运行它,我都会收到这个异常

java.lang.AssertionError: expected object to not be null

我想我在模拟测试中做错了什么。有什么建议可以帮我解决吗?

3个回答

44

要做到这一点,您可以使用 PowerMockito.spy(...)PowerMockito.doReturn(...)

此外,您必须在测试类中指定 PowerMock runner,并准备好要测试的类,如下所示:

@PrepareForTest(Util.class)
@RunWith(PowerMockRunner.class)
public class UtilTest {

   @Test
   public void testMethod() throws Exception {
      PowerMockito.spy(Util.class);
      PowerMockito.doReturn("abc").when(Util.class, "anotherMethod");

      String retrieved = Util.method();

      Assert.assertNotNull(retrieved);
      Assert.assertEquals(retrieved, "abc");
   }
}

希望能对您有所帮助。


2
如果您已经使用PowerMock运行器指定了一个类,请像这样添加第二个类:@PrepareForTest({First.class,Util.class}) - Ilker Cat
获取的字符串为:retrieved = Util.anotherMethod(); 静态方法的名称不是_method_,而是anotherMethod。 - Stevers
@Stevers method() 是从测试中调用的公共静态方法。anotherMethod() 是被模拟的方法。答案是正确的,请再次检查 OP。 - troig
解决方案并没有真正提到原始解决方案的问题所在。原始解决方案使用了一个模拟对象,这意味着整个对象都是假的,其中的方法没有被定义。作者只为方法“anotherMethod”定义了它被调用时应该如何行为。但他没有为方法“method”定义相同的方式。这就是为什么调用“method”会返回null,甚至不会调用“anotherMethod”的原因。使用spy我们使用真实对象和所有方法都是真实方法。另一种解决方案是使用模拟对象并使用.callRealMethod来执行“method”。 - sakal

10
如果anotherMethod()需要传入参数,那么正确调用该方法的方式是: anotherMethod(parameter)。
PowerMockito.doReturn("abc").when(Util.class, "anotherMethod", parameter);

-1

我不确定您正在使用哪个版本的PowerMock,但是在较新的版本中,应该使用 @RunWith(PowerMockRunner.class) @PrepareForTest(Util.class)

话虽如此,我发现使用PowerMock真的很有问题,这是设计不良的肯定迹象。如果您有时间/机会更改设计,我会尝试首先这样做。


不,对于TestNG,我需要使用我的注释。 - Aaron
对于那些需要使用不同的运行器而无法使用PowerMockRunner的人,可以使用@Rule注释代替:@Rule public PowerMockRule rule = new PowerMockRule(); - Dave Birch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接