在本文中,我将快速向您展示如果您需要解决以下挑战,那么JUnit规则有多方便
方法捕获异常并必须执行一些额外的任务,然后再抛出或引发包装异常。
调用额外任务和引发的异常应通过单元测试进行验证。
这意味着您有一些这样的代码
public class MyThrowingClass {
private final ExceptionProcessor exceptionProcessor;
public MyThrowingClass(ExceptionProcessor exceptionProcessor) {
this.exceptionProcessor = exceptionProcessor;
}
public void runTask() throws NullPointerException {
try {
// something to do here
throw new NullPointerException("It's null Jim");
} catch (NullPointerException e) {
exceptionProcessor.process(e); // This call needs to be verified
throw e;
}
}
}
并在这行中
exceptionProcessor.process(e);
需要进行验证以及引发异常。
直截了当…但是丑陋
我不会详细介绍此变体
try {
cut.runMyMethod();
} catch(Exception e) {
verify(...);
assertThat(e).isInstanceOf();
}
因为我个人尽量避免在测试代码中尝试捕获结构。
容易的第一
验证引发异常相当容易,JUnit在此处提供了潜在的选项
- @Test批注的预期参数和
- 一个叫做ExceptionRule的规则
第一个选项看起来像这样
@Test(expected = NullPointerException.class)
public void myTestWithExpectedParameter() throws Exception {
// ...
}
第二个像这样
// ...
@Rule
public ExceptionRule exceptionRule = ExceptionRule.none();
// ...
@Test
public void myTestWithTheExceptionRule() throws Exception {
exceptionRule.expect(NullPointerException.class);
// ...
}
不,它变得越来越复杂
上述测试要求背后的问题如下
执行被测方法之后,您执行的所有verify(…)步骤将不会执行,因为如果引发并没有捕获到异常,异常将照常停止其余测试方法的执行。
JUnit救援规则
借助JUnit规则,我们即使在引发异常的情况下,也可以轻松地提供一种提供其他验证步骤的方法。
我知道JUnit已经提供了验证程序规则,但是我不会使用它。 该类的缺点是在设置时将验证逻辑刻录到其中。
因此,我们需要一个规则,该规则允许我们为每个测试指定一个额外的验证逻辑,该逻辑将在测试执行后应用。
一般用法如下所示
@Rule
public VerifyRule verifyRule = new VerifyRule();
@Mock
ExceptionProcessor exceptionProcessor;
@Test()
public void working() throws Exception {
verifyRule.setVerifier(() -> verify(exceptionProcessor).process(any()));
// ..
}
为了使它运行起来,我们需要做一些事情
- 验证规则
- 可以在验证规则上设置的任何类型的回调接口
让我们从回调接口开始
public interface VerifyRuleCallback {
void execute() throws Throwable;
}
如您所见,这里没什么特别的。
现在,让我们专注于VerifyRule
public class VerifyRule implements TestRule {
private VerifyRuleCallback verifyRuleCallback;
@Override
public Statement apply(Statement base, Description description) {
return new VerifyRuleStatement(base);
}
public void setVerifier(VerifyRuleCallback verifyRuleCallback) {
this.verifyRuleCallback = verifyRuleCallback;
}
private class VerifyRuleStatement extends Statement {
private final Statement nextStatement;
public VerifyRuleStatement(Statement nextStatement) {
this.nextStatement = nextStatement;
}
@Override
public void evaluate() throws Throwable {
nextStatement.evaluate();
verifyRuleCallback.execute();
}
}
}
如您所见,它实现了TestRule接口,并提供了一种设置VerifyRuleCallback的方法。 然后,在需要执行以运行我们自己的回调评估的VerifyRuleStatement的评估方法中使用该回调。
绑在一起
使用新规则和回调,测试可能看起来像这样
public class MyThrowingClassShould {
@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
@InjectMocks
MyThrowingClass cut;
@Mock
ExceptionProcessor processor;
@Rule
public ExpectedException exception = ExpectedException.none();
@Rule
public VerifyRule verifyRule = new VerifyRule();
@Test()
public void execute_the_exception_processor_and_rethrow_the_exception_when_it_occur() throws Exception {
verifyRule.setVerifier(() -> verify(processor).process(any(NullPointerException.class)));
exception.expect(NullPointerException.class);
cut.runTask();
}
}
摘要
正如我们已经看到的那样,JUnit规则不仅在这种情况下,而且还提出了这样的测试要求时,提供了一种非常简洁的方法来创建清晰易懂的测试代码。
的JUnit 2016-09-26