JUnit:使用构造函数而不是@Before

时间:2011-05-23 07:22:27

标签: constructor junit initialization

我正在使用JUnit 4.我看不出构造函数初始化或使用@Before注释的专用init函数之间的区别。这是否意味着我不必担心它?

@Before提供的不仅仅是在构造函数中初始化的情况吗?

9 个答案:

答案 0 :(得分:75)

不,使用构造函数初始化JUnit测试夹具在技术上等同于使用@Before方法(由于JUnit为每个@Test创建测试类的新实例)。唯一(内涵)差异在于它打破了@Before@After之间的对称性,这可能会使某些人感到困惑。恕我直言,最好遵守惯例(使用@Before)。

另请注意,在JUnit 4和注释之前,有专门的setUp()tearDown()方法 - @Before@After注释替换了这些,但保留了基础逻辑。因此,使用注释还可以使从JUnit 3或更早版本迁移的人员的生活更轻松。

显着差异

评论的更多细节:

  • @Before允许重写父类行为,构造函数强制您调用父类构造函数
  • 构造函数在子类构造函数和@Rule方法之前运行@Before之后运行
  • 调用@Before导致@After方法时出现异常,构造函数中的异常不

答案 1 :(得分:25)

@Before在某些情况下使用更有意义,因为它在类的构造函数之后被调用。当您使用像Mockito这样的模拟框架和@Mock注释时,这种差异非常重要,因为在模拟初始化之后将调用@Before方法。然后,您可以使用模拟为被测试的类提供构造函数参数。

在使用协作bean时,我发现这是我单元测试中非常常见的模式。

这是一个(公认的做作)例子:

@RunWith(MockitoJUnitRunner.class)
public class CalculatorTest {
    @Mock Adder adder;
    @Mock Subtractor subtractor;
    @Mock Divider divider;
    @Mock Multiplier multiplier;

    Calculator calculator;

    @Before
    public void setUp() {
        calculator = new Calculator(adder,subtractor,divider,multiplier);
    }

    @Test
    public void testAdd() {
        BigDecimal value = calculator.add(2,2);
        verify(adder).add(eq(2),eq(2));
    }
}

答案 2 :(得分:7)

我更喜欢使用构造函数来初始化我的测试对象,因为它允许我创建所有成员final,以便IDE或编译器告诉我构造函数何时忘记初始化成员并阻止另一种方法设置它们。

恕我直言,@Before违反了最重要的Java约定之一,即依赖构造函数来完全初始化对象!

答案 3 :(得分:5)

我更喜欢将我的灯具声明为final并在内联或构造函数中初始化它们,所以我不会忘记初始化它们!但是,由于@Before中抛出的异常以更加用户友好的方式处理,我通常会在@Before中初始化测试中的对象。

答案 4 :(得分:1)

@Before在任何@Test之前被调用,而不是每个Test-Class一次 这可用于为每个特定测试重置/初始化数据(例如将变量重置为特定值等)。

在同一个Fashion @After中,可以在执行@Test方法后清理代码。

请参阅:http://junit.sourceforge.net/javadoc/org/junit/Before.html

答案 5 :(得分:1)

构造函数有一件事可以存档但不能 @Before

当您需要在父类中定义的初始字段时,必须使用构造函数。例如:

abstract class AbstractIT {
   int fieldAssignedInSubClass;
   public AbstractIT(int fieldAssignedInSubClass) {
      this.fieldAssignedInSubClass= fieldAssignedInSubClass;
   }

   @Before
   void before() {
      // comsume fieldAssignedInSubClass
   } 
}

public class ChildIT extends AbstractIT{
   public ChildIT() {
      // assign fieldAssignedInSubClass by constructor
      super(5566); 
   }

   @Before
   void before() {
      // you cannot assign fieldAssignedInSubClass by a @Before method
   } 
}

答案 6 :(得分:1)

引用http://etutorials.org/Programming/Java+extreme+programming/Chapter+4.+JUnit/4.6+Set+Up+and+Tear+Down/

  

您可能想知道为什么应该编写setUp()方法而不是   只需在测试用例的构造函数中初始化字段即可。毕竟,   因为为每个测试创建了一个新的测试用例实例   方法中,构造函数总是在setUp()之前调用。在广阔的   在大多数情况下,您可以使用构造函数代替setUp()   没有任何副作用。

     

如果您的测试用例是更深层次的继承的一部分   层次结构,您可能希望将对象初始化推迟到   派生类的实例已完全构建。这很好   您可能想使用setUp()而不是   初始化的构造函数。使用setUp()和tearDown()也是   很好地用于文档目的,仅因为它可以编写代码   更容易阅读。

答案 7 :(得分:0)

出于几个原因,

@Before使用有意义。它使您的测试代码更具可读性。它匹配@After注释,该注释负责释放已使用的资源,并且是@BeforeClass注释的对应部分。

答案 8 :(得分:0)

除了构造函数是唯一可以初始化@Rule对象的方法之外没有区别:

public class TestClass {

    @Rule
    public SomeRule rule;

    public TestClass() {
        // code to initialize the rule field
        conf = new RuleConf()
        rule = new SomeRule(conf)
    }
}