为什么 jUnit 的 fixtureSetup 必须是静态的?

2022-08-31 09:11:10

我用jUnit的@BeforeClass注释标记了一个方法,并得到了这个异常,说它必须是静态的。理由是什么?这迫使我所有的 init 都位于静态场上,据我所知,这是没有充分理由的。

在 .Net (NUnit) 中,情况并非如此。

编辑 - 用@BeforeClass注释的方法只运行一次的事实与它是静态方法无关 - 一个非静态方法只能运行一次(如在NUnit中)。


答案 1

JUnit 始终为每个@Test方法创建一个测试类实例。这是一个基本的设计决策,可以更轻松地编写没有副作用的测试。好的测试没有任何运行顺序依赖关系(参见 F.I.R.S.T),为每个测试创建测试类的新实例及其实例变量对于实现这一目标至关重要。某些测试框架对所有测试都重用相同的测试类实例,这会导致在测试之间意外产生副作用的可能性更大。

而且,由于每个测试方法都有自己的实例,因此将@BeforeClass/@AfterClass方法作为实例方法毫无意义。否则,应在哪个测试类实例上调用这些方法?如果@BeforeClass/@AfterClass方法可以引用实例变量,则@Test方法中只有一个可以访问这些相同的实例变量 - 其余的将具有默认值的实例变量 - 并且@Test方法将被随机选择,因为.class文件中的方法顺序是未指定/与编译器相关的(IIRC, Java的反射API以与.class文件中声明相同的顺序返回方法,尽管该行为也是未指定的 - 我已经编写了一个库,用于按行号对它们进行排序)。

因此,将这些方法强制为静态是唯一合理的解决方案。

下面是一个示例:

public class ExampleTest {

    @BeforeClass
    public static void beforeClass() {
        System.out.println("beforeClass");
    }

    @AfterClass
    public static void afterClass() {
        System.out.println("afterClass");
    }

    @Before
    public void before() {
        System.out.println(this + "\tbefore");
    }

    @After
    public void after() {
        System.out.println(this + "\tafter");
    }

    @Test
    public void test1() {
        System.out.println(this + "\ttest1");
    }

    @Test
    public void test2() {
        System.out.println(this + "\ttest2");
    }

    @Test
    public void test3() {
        System.out.println(this + "\ttest3");
    }
}

哪些打印:

beforeClass
ExampleTest@3358fd70    before
ExampleTest@3358fd70    test1
ExampleTest@3358fd70    after
ExampleTest@6293068a    before
ExampleTest@6293068a    test2
ExampleTest@6293068a    after
ExampleTest@22928095    before
ExampleTest@22928095    test3
ExampleTest@22928095    after
afterClass

如您所见,每个测试都是使用自己的实例执行的。JUnit的作用基本上是相同的:

ExampleTest.beforeClass();

ExampleTest t1 = new ExampleTest();
t1.before();
t1.test1();
t1.after();

ExampleTest t2 = new ExampleTest();
t2.before();
t2.test2();
t2.after();

ExampleTest t3 = new ExampleTest();
t3.before();
t3.test3();
t3.after();

ExampleTest.afterClass();

答案 2

简短的答案是:没有充分的理由让它保持静态。

事实上,如果您使用 Junit 执行基于 DBUnit 的 DAO 集成测试,则将其设为静态会导致各种问题。静态要求会干扰依赖关系注入、应用程序上下文访问、资源处理、日志记录以及依赖于“getClass”的任何内容。


推荐