我想知道在编写JUnit测试时,以下是否存在任何技术差异:
选项1:
定义一个设置方法,即用@Before
注释,以在运行任何@Test
方法之前初始化测试夹具状态。
选项2:
定义一个私有方法 - 只是一个没有任何注释的普通旧私有方法 - 执行相同的初始化,并使每个@Test
方法的第一行调用此方法。 (忽略在每次测试中都有人忘记调用该方法的可能性。我正在寻找技术差异,而不是人为因素)
选项2的示例:
public class MyTest {
private void runSetupLogic() {
// whatever @Before method would have done
}
@Test
public void testMethod1() {
runSetupLogic();
// test logic
}
@Test
public void testMethod2() {
runSetupLogic();
// test logic
}
}
答案 0 :(得分:2)
我不相信。
但是,如果您实现了另一个函数,例如 tearDown(),它基本上可以用作 @After 方法,我会认为你可能会这样做好好利用它们的可读性,为了其他合作者甚至自己的利益。
使用 @Before 和 @After 注释的好处是他们避免在每个单元测试开始时调用方法,旨在为您节省额外的维护。如果由于某种原因您忘记将调用添加到 setUp()和/或 tearDown()方法,谁知道哪些内容可能出错。
当然,如果您在每次测试之前需要完全相同的设置。如果您想要为不同的单元测试设置完全不同的设置,那么您可能应该查看正在测试的类的功能,并问自己是否可以模块化更多。
答案 1 :(得分:2)
它们并非真正完全相同,但是对于所有意图和目的,任何一种方式都应该没问题。但是,如果您对技术分析感兴趣,那么我对Github上当前JUnit 4代码的不清楚理解如下:
使用默认的JUnit 4 runner [{3}} @Before
时,使用/**
* Returns a {@link Statement}: run all non-overridden {@code @Before}
* methods on this class and superclasses before running {@code next}; if
* any throws an Exception, stop execution and pass the exception on.
*/
protected Statement withBefores(FrameworkMethod method, Object target,
Statement statement) {
List<FrameworkMethod> befores = getTestClass().getAnnotatedMethods(
Before.class);
return befores.isEmpty() ? statement : new RunBefores(statement,
befores, target);
}
时,似乎是运行的实际代码:
public class RunBefores extends Statement {
private final Statement next;
private final Object target;
private final List<FrameworkMethod> befores;
public RunBefores(Statement next, List<FrameworkMethod> befores, Object target) {
this.next = next;
this.befores = befores;
this.target = target;
}
@Override
public void evaluate() throws Throwable {
for (FrameworkMethod before : befores) {
before.invokeExplosively(target);
}
next.evaluate();
}
以上调用src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java中的RunBefores:
public Object invokeExplosively(final Object target, final Object... params)
throws Throwable {
return new ReflectiveCallable() {
@Override
protected Object runReflectiveCall() throws Throwable {
return method.invoke(target, params);
}
}.run();
}
invokeExplosively方法定义位于src/main/java/org/junit/internal/runners/statements/RunBefores.java:
@Before
似乎使用反射来调用用@Before
注释的方法。
无论如何,希望这个答案有点正确,但我不确定。如果有人有任何更正,我可以从评论中编辑它们。顺便提一下,这里引用的是{{1}}注释的javadoc:src/main/java/org/junit/runners/model/FrameworkMethod.java
答案 2 :(得分:1)
好处来自报道。
在您的方法中:runSetupLogic()
从测试开始运行时,在测试中报告。不是设置的一部分,也不是初始化的一部分。
如果设置方法失败,您可以准确描述失败的设置...设置与测试。
before方法允许您将测试失败与设置失败隔离开来,并允许报告解决方案。