简体   繁体   English

在任何测试步骤之前,在每个JUnit中调用一个私有方法

[英]Calling a private method inside every JUnit before any test steps

I want to know if there is any technical difference between the following, when writing JUnit tests: 我想知道在编写JUnit测试时以下内容之间是否存在技术上的区别:

Option 1: Define a setup method, ie annotated with @Before , to initialize test fixture state before any @Test method is run. 选项1:定义一个设置方法,即使用@Before注释,以在运行任何@Test方法之前初始化测试治具的状态。

Option 2: Define a private method - just a plain old private method without any annotation - that does the same initialization, and make the first line of every @Test method a call to this method. 选项2:定义一个私有方法-只是一个普通的老式私有方法,没有任何注释-进行相同的初始化,并将每个@Test方法的第一行称为对此方法的调用。 (Ignore the possibility of someone forgetting to call the method in every test. I am looking for technical differences, not human factors) (忽略有人在每次测试中忘记调用该方法的可能性。我在寻找技术差异,而不是人为因素)

Example of Option 2: 选项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
    }
}

I do not believe so. 我不相信。
However, if you were you implement another function, such as tearDown() , that would function essentially as an @After method, I would argue you might as well use them for readability, for the benefit of other collaborators or maybe even yourself. 但是,如果您要实现另一个函数,例如tearDown() ,则该函数实际上将用作@After方法,我认为您最好将它们用于可读性,以使其他协作者甚至您自己受益。

The upside to using @Before and @After annotations is the that they avoid having to call a method at the beginning of each unit test, designed to save you the extra maintenance. 使用@Before@After注释的好处是,它们避免在每次单元测试开始时都必须调用方法,这是为了节省您的额外维护。 If for some reason you had forgotten to add the call to your setUp() and/or tearDown() method, who knows what could go wrong. 如果由于某种原因您忘记将调用添加到setUp()和/或tearDown()方法中,谁知道会出问题。

This is, of course, if you need the EXACT SAME setup before each test. 当然,这是在每次测试之前都需要完全相同的设置。 If you envision having a completely different setup for different unit tests, than perhaps you should look at the functionality of the class you are testing and ask yourself if perhaps you could modularize more. 如果您打算为完全不同的单元测试设置完全不同的设置,那么也许您应该查看所测试类的功能,并问自己是否可以进一步模块化。

They are not really exactly the same, but for all intents and purposes either way should be fine. 它们实际上并不完全相同 ,但是无论从哪方面来看,任何一种方法都应该是正确的。 However, if you are interested in the technical analysis then my shaky understanding of the current JUnit 4 code on Github follows: 但是,如果您对技术分析感兴趣,那么我对Github上当前的JUnit 4代码的理解就会有些不稳定:

Here is what seems to be the actual code being ran when you use @Before using the default JUnit 4 runner src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java : 这是当您使用@Before使用默认的JUnit 4运行程序src / main / java / org / junit / runners / BlockJUnit4ClassRunner.java时,似乎正在运行的实际代码:

/**
 * 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);
}

The above calls RunBefores in src/main/java/org/junit/internal/runners/statements/RunBefores.java : 上面在src / main / java / org / junit / internal / runners / statements / RunBefores.java中调用RunBefores

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();
    }

The invokeExplosively method definition is in src/main/java/org/junit/runners/model/FrameworkMethod.java : invokeExplosively方法定义位于src / main / java / org / junit / runners / model / FrameworkMethod.java中

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();
}

which seems to use reflection to invoke the methods annotated with @Before . 这似乎使用反射来调用@Before注释的方法。

Anyway, hope this answer is somewhat correct, but I'm not sure. 无论如何,希望这个答案是正确的,但是我不确定。 If anyone has any corrections I can edit them in from the comments. 如果任何人有任何更正,我可以从注释中对其进行编辑。 By the way, for reference here is the javadoc for the @Before annotation: http://junit.org/javadoc/latest/org/junit/Before.html 顺便说一句,这里提供@Before注释的Javadoc: http : @Before

The benifit comes from reporting. 好处来自于报告。

In your method: runSetupLogic() 在您的方法中:runSetupLogic()

when ran from the start of a test, is reported within the test. 从测试开始运行时,将在测试内报告。 Not as part of the setup and not as part of the initialization. 不作为设置的一部分,也不作为初始化的一部分。

If the setup method fails, you get an accurate description of what failed... setup vs testing. 如果安装方法失败,您将准确了解失败的原因...安装与测试。

The before method allows you to isolate test failures from setup failures and allows the reporting solution to know as well. 使用before方法,您可以将测试失败与设置失败隔离开来,并使报告解决方案也可以知道。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM