将 PoweMock 与 PowerMockRule 一起使用时,使用 ExpectedException 进行的测试失败
Test with ExpectedException fails when using PoweMock with PowerMockRule
我正在尝试使用 PowerMock,而不是 Mockito;因为我喜欢 API 的 whennew() 和 verifyprivate() 但是我在 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,这会成功,但一些模拟方法会抛出异常。
我能够使用 @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");
}
}
PowerMock 创建 TestExpectedExceptionRule
对象的深度克隆。因此,它是 运行 具有新 ExpectedException
规则的测试,但您在原始规则上调用 exception.expect (NullPointerException.class)
。因此测试失败,因为 ExpectedException
规则的克隆不期望异常。
尽管如此,您的问题至少有两种解决方案。
规则链
使用 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());
}
没有Java8,你必须使用匿名class。
@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());
}
我通过创建一个使用 FunctionalInterface
.
的 PowerMockTestUtil
class 解决了这个问题
效用 class:
/**
* 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;
}
}
样本测试:
@Test
public void testValidateMissingQuantityForNewItem() throws Exception {
...
expectException(() -> catalogEntryAssociationImporter.validate(line),
ImportValidationException.class,
"Quantity is required for new associations");
}
我正在尝试使用 PowerMock,而不是 Mockito;因为我喜欢 API 的 whennew() 和 verifyprivate() 但是我在 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,这会成功,但一些模拟方法会抛出异常。
我能够使用 @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");
}
}
PowerMock 创建 TestExpectedExceptionRule
对象的深度克隆。因此,它是 运行 具有新 ExpectedException
规则的测试,但您在原始规则上调用 exception.expect (NullPointerException.class)
。因此测试失败,因为 ExpectedException
规则的克隆不期望异常。
尽管如此,您的问题至少有两种解决方案。
规则链
使用 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());
}
没有Java8,你必须使用匿名class。
@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());
}
我通过创建一个使用 FunctionalInterface
.
PowerMockTestUtil
class 解决了这个问题
效用 class:
/**
* 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;
}
}
样本测试:
@Test
public void testValidateMissingQuantityForNewItem() throws Exception {
...
expectException(() -> catalogEntryAssociationImporter.validate(line),
ImportValidationException.class,
"Quantity is required for new associations");
}