将PowerMock与PowerMockRule一起使用时,使用预期异常进行测试失败

时间:2015-02-11 01:10:54

标签: junit powermock

我正在尝试使用PowerMock,而不是Mockito;因为我喜欢用于whennew()和verifyprivate()的API,但是在尝试使用Junit中的类别TestRunner运行测试套件时遇到了一些问题。

为了使用默认的JUnit测试运行器,我创建了一个TestCase并添加了 PowerMockRule作为带有@Rule注释的实例字段。虽然执行测试的工作方式如此,但 ExpectedException TestRule在结合使用时不起作用

示例代码

@PowerMockIgnore ("*")
@PrepareForTest (CustomizedSSHConnection.class)
public class TestExpectedExceptionRule {

    private Connection          connection;
    private ConnectionInfo      connectionInfo;
     @Rule
     public PowerMockRule rule = new PowerMockRule ();
    @Rule
    public ExpectedException    exception   = ExpectedException.none ();

    @Test
    public void testExcepitonWithPowerMockRule() {
        exception.expect (NullPointerException.class);
        exception.expectMessage ("Image is null");
        throw new NullPointerException ("Image is null");
    }
}

如果我使用@RunWith(PowerMockRunner.class),而不是使用@Rule PowerMockRule,则此测试用例将通过。

另一个观察是,如果我使用@ClassRule注释PowerMockRule,这会成功但是一些模拟方法会抛出异常。

3 个答案:

答案 0 :(得分:2)

PowerMock创建TestExpectedExceptionRule对象的深层克隆。因此,它使用新的ExpectedException规则运行测试,但您在原始规则上调用exception.expect (NullPointerException.class)。因此测试失败,因为ExpectedException规则的克隆不期望异常。

尽管如此,至少有两种解决方案可以解决您的问题。

RuleChain

使用JUnit的RuleChain订购规则。这需要一些额外的丑陋代码,但它可以工作。

private ExpectedException exception = ExpectedException.none ();
private PowerMockRule powerMockRule = new PowerMockRule();

@Rule
public TestRule ruleChain = RuleChain.outerRule(new TestRule() {
    @Override
    public Statement apply(Statement base, Description description) {
        return powerMockRule.apply(base, null, description);
    }
}).around(exception);

鱼缸

如果您使用的是Java 8,则可以将ExpectedException规则替换为Fishbowl库。

@Test
public void testExcepitonWithPowerMockRule() {
  Throwable exception = exceptionThrownBy(
    () -> throw new NullPointerException ("Image is null"));
  assertEquals(NullPointerException.class, exception.getClass());
  assertEquals("Image is null", exception.getMessage());
}

如果没有Java 8,则必须使用匿名类。

@Test
public void fooTest() {
  Throwable exception = exceptionThrownBy(new Statement() {
    public void evaluate() throws Throwable {
      throw new NullPointerException ("Image is null");
    }
  });
  assertEquals(NullPointerException.class, exception.getClass());
  assertEquals("Image is null", exception.getMessage());
}

答案 1 :(得分:0)

我通过创建一个使用PowerMockTestUtil的{​​{1}}类解决了这个问题。

实用程序类:

FunctionalInterface

样本测试:

/**
 * Utility class to provide some testing functionality that doesn't play well with Powermock out
 * of the box. For example, @Rule doesn't work well with Powermock.
 */
public class PowerMockTestUtil {

  public static void expectException(RunnableWithExceptions function, Class expectedClass, String expectedMessage) {
    try {
      function.run();
      fail("Test did not generate expected exception of type " + expectedClass.getSimpleName());
    } catch (Exception e) {
      assertTrue(e.getClass().isAssignableFrom(expectedClass));
      assertEquals(expectedMessage, e.getMessage());
    }
  }

  @FunctionalInterface
  public interface RunnableWithExceptions<E extends Exception> {
    void run() throws E;
  }
}

答案 2 :(得分:-1)

我能够使用@Test注释中的预期属性来修复此问题。但是这种方法的问题是我无法断言异常消息。这对我来说现在很好。

@PowerMockIgnore ("*")
@PrepareForTest (CustomizedSSHConnection.class)
public class TestExpectedExceptionRule {

    private Connection          connection;
    private ConnectionInfo      connectionInfo;
     @Rule
     public PowerMockRule rule = new PowerMockRule ();
    @Rule
    public ExpectedException    exception   = ExpectedException.none ();

    @Test(expected = NullPointerException.class)
    public void testExcepitonWithPowerMockRule() {
        throw new NullPointerException ("Image is null");
    }
}