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

rip*_*234 105 java junit

我用jUnit的@BeforeClass注释标记了一个方法,得到了这个例外,说它必须是静态的.理由是什么?这迫使我所有的init都在静态字段上,据我所知,这是没有充分理由的.

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

编辑 - 使用@BeforeClass注释的方法只运行一次与静态方法无关 - 可以使非静态方法只运行一次(如在NUnit中).

Esk*_*ola 119

JUnit 总是为每个@Test方法创建一个测试类实例.这是一个基本的设计决策,可以更轻松地编写没有副作用的测试.良好的测试没有订单的运行任何依赖关系(见FIRST)和测试类的创建新实例,实例变量对每个测试是在实现这一目标至关重要.一些测试框架为所有测试重用相同的测试类实例,这导致在测试之间意外地产生副作用的更多可能性.

并且因为每个测试方法都有自己的实例,所以将@ BeforeClass/@ AfterClass方法作为实例方法是没有意义的.否则,应该在哪个测试类实例上调用这些方法?如果它会为@ BeforeClass/@课余方法可以参考的实例变量,那么只有的@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");
    }
}
Run Code Online (Sandbox Code Playgroud)

哪个印刷品:

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
Run Code Online (Sandbox Code Playgroud)

如您所见,每个测试都使用自己的实例执行.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();
Run Code Online (Sandbox Code Playgroud)


HDa*_*ave 42

简短的回答是: 它没有充分理由是静态的.

实际上,如果使用Junit执行基于DBUnit的DAO集成测试,使其静态会导致各种问题.静态需求会干扰依赖注入,应用程序上下文访问,资源处理,日志记录以及依赖于"getClass"的任何内容.

  • 这是一个可怕的答案,显然事实上有一个理由是它是静态的,因为接受的答案清楚地表明了.您可能不同意设计决策,但这并不意味着该决定"没有充分理由". (9认同)
  • 当然,JUnit的作者有一个理由,我说它不是一个好的理由......因此OP(以及另外44个人)的来源是神秘的.使用实例方法并让测试运行器使用约定来调用它们本来是微不足道的.最后,这就是每个人为解决这个限制而做的事情 - 要么推出自己的跑步者,要么推出自己的测试类. (8认同)
  • 我编写了自己的测试用例超类,并使用Spring注释`@ PostConstruct`进行设置,使用`@ AfterClass`进行拆除,我完全忽略了Junit中的静态注释.对于DAO测试,我然后编写了自己的`TestCaseDataLoader`类,我从这些方法调用它. (4认同)

Bla*_*rad 12

JUnit文档似乎很少,但我猜:在运行每个测试用例之前,JUnit可能会创建一个新的测试类实例,因此"fixture"状态持续运行的唯一方法是让它保持静态,这可以通过确保您的fixtureSetup(@BeforeClass方法)是静态的来强制执行.

  • 不仅可能,但JUnit肯定会创建一个测试用例的新实例.所以这是唯一的原因. (2认同)