Junit - 多个@Before与一个@Before分成方法

时间:2012-02-03 15:25:44

标签: java junit

在单元测试中,我需要执行一个相当复杂的设置(这可能是代码味道,但这不是这个问题的内容:-))。我感兴趣的是,如果最好有多个@Before方法执行设置或只有一个,它调用辅助方法来执行初始化。

E.g。

@Before
public void setUpClientStub() {

}

@Before
public void setUpObjectUnderTest() {

}

VS

@Before
public void setUp() {
    setUpClientStub();
    setUpObjectUnderTest();
}

6 个答案:

答案 0 :(得分:31)

正如在其他响应中所述,JUnit找到方法的顺序无法保证,因此无法保证@Before方法的执行顺序。 @Rule也是如此,它同样缺乏保证。如果这将始终是相同的代码,那么分成两个方法没有任何意义。

如果你有两种方法,更重要的是,如果你想在多个地方使用它们,那么你可以使用4.10中引入的RuleChain来组合规则。这允许规则的特定顺序,例如:

public static class UseRuleChain {
  @Rule
  public TestRule chain= RuleChain
               .outerRule(new LoggingRule("outer rule"))
               .around(new LoggingRule("middle rule"))
               .around(new LoggingRule("inner rule"));

  @Test
  public void example() {
      assertTrue(true);
  }
}

这会产生:

starting outer rule
starting middle rule
starting inner rule
finished inner rule
finished middle rule
finished outer rule

所以你可以升级到4.10或者只是偷走课程。

在您的情况下,您可以定义两个规则,一个用于客户端设置,一个用于对象,并将它们组合在RuleChain中。使用ExternalResource

public static class UsesExternalResource {
  private TestRule clientRule = new ExternalResource() {
      @Override
      protected void before() throws Throwable {
        setupClientCode();
      };

      @Override
      protected void after() {
        tearDownClientCode()
    };
  };

  @Rule public TestRule chain = RuleChain
                   .outerRule(clientRule)
                   .around(objectRule);
}

所以你将拥有以下执行顺序:

clientRule.before()
objectRule.before()
the test
objectRule.after()
clientRule.after()

答案 1 :(得分:7)

我会做后者。 AFAIK,无法保证@Before带注释的设置方法的顺序。

答案 2 :(得分:4)

请注意,无法保证调用@Before带注释的方法的顺序。如果它们之间存在某些依赖关系(例如,必须在另一个方法之前调用一个方法),则必须使用后一种形式。

否则这是一个偏好的问题,只需将它们放在一个地方,这样就很容易发现它们。

答案 3 :(得分:3)

我认为它没有多大区别,但我个人更喜欢第二种方法(方法执行之前的顺序没有定义,你会有更好的控制方式)。

答案 4 :(得分:0)

对我来说,似乎使用JUnit 4.12,用@Before注释的方法确实通过以下特征进行了确定性的确定确定

按相反的字典顺序(相对于方法名称)。

您可以通过执行以下Testclass来查看此行为:

import java.util.Arrays;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

/*
 * key points:
 * - multiple @Before methods get sorted by reversed lexicographic order 
 * */
public class JUnitLifecyle {

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

    public JUnitLifecyle() {
        System.out.println("Constructor");
    }

    @Before
    public void a() {
        System.out.println("@Before a");
    }

    @Before
    public void b() {
        System.out.println("@Before b");
    }

    @Before
    public void cd() {
        System.out.println("@Before cd");
    }

    @Before
    public void ca() {
        System.out.println("@Before ca");
    }

    @Before
    public void cc() {
        System.out.println("@Before cc");
    }

    @Before
    public void d() {
        System.out.println("@Before d");
    }

    @Before
    public void e() {
        System.out.println("@Before e");
    }

    @Test
    public void firstTest() {
        System.out.println("@Test 1");
    }

    @Test
    public void secondTest() {
        System.out.println("@Test 2");
    }

    @After
    public void runsAfterEveryTestMethod() {
        System.out.println("@After");
    }

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

我在处理输出之后,更改了用@Before注释的方法的方法名称,得出了这个结论。

请牢记颠倒的字典顺序,您可以相应地命名方法,以使JUnit以正确的顺序执行设置任务。

尽管可以采用上述方法,但是我认为您不应在测试中这样做,因为JUnit中引入了Java-Annotations来摆脱基于约定的测试。

答案 5 :(得分:0)

我将我的所有@Before方法声明为私有,并创建了一个用@Before注释的方法,该方法调用了所有这些方法,并且我的测试有效。我在科特林工作过。 这是您的操作方法:

private fun setUpClientStub() {
     //whatever you want to do
}

private fun setUpObjectUnderTest() {
    //whatever you want to do
}

@Before
fun setUp() {
    setUpClientStub()
    setUpObjectUnderTest()
}

@Test
fun test() {
   //your test logic
}

这样,您可以确保以正确的顺序调用方法,并且可以根据需要命名它们。