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

问题描述 投票:0回答:8

我正在使用 JUnit 4。我看不出在构造函数中初始化或使用由

@Before
注释的专用 init 函数之间的区别。这是否意味着我不必担心?

是否存在

@Before
不仅仅在构造函数中进行初始化的情况?

java junit constructor initialization
8个回答
110
投票

不,使用构造函数初始化 JUnit 测试装置在技术上等同于使用

@Before
方法(因为 JUnit 为每个
@Test
创建了测试类的新实例)。唯一的(内涵)区别是它打破了
@Before
@After
之间的对称性,这可能会让一些人感到困惑。恕我直言,最好遵守约定(使用
@Before
)。

另请注意,在 JUnit 4 和注释之前,有专用的

setUp()
tearDown()
方法 -
@Before
@After
注释取代了这些方法,但保留了底层逻辑。因此,使用注释还可以让从 JUnit 3 或更早版本迁移的人的生活更轻松。

显着差异

来自评论的更多详细信息:

  • @Before
    允许重写父类行为,构造函数强制你调用父类构造函数
  • 构造函数在之前子类构造函数和
    @Rule
    方法运行,
    @Before
    之后所有这些运行
  • @Before
    期间的异常会导致调用
    @After
    方法,构造函数中的异常则不会

32
投票

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

14
投票

我更喜欢使用构造函数来初始化我的测试对象,因为它允许我创建所有成员

final
,以便IDE或编译器会告诉我何时构造函数忘记初始化成员并防止其他方法设置它们。

恕我直言,

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

JUnit 5 还对构造函数注入提供了更好的支持。


5
投票

我更喜欢将我的装置声明为最终的,并内联或在构造函数中初始化它们,这样我就不会忘记初始化它们!不过,由于 @Before 中抛出的异常会以更人性化的方式处理,所以我通常会在 @Before 中初始化被测对象。


4
投票

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

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

如果您的测试用例是更深层次继承的一部分 层次结构,您可能希望推迟对象初始化直到 派生类的实例已完全构造。这是一个很好的 您可能想要使用 setUp( ) 而不是 a 的技术原因 用于初始化的构造函数。使用setUp()和tearDown()也是 适合文档目的,只是因为它可能会使代码 更容易阅读。


1
投票

有一件事是 constructor 可以存档,但 @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
   } 
}

0
投票

@Before
的使用确实有意义,有几个原因。它使您的测试代码更具可读性。它与
@After
注释匹配,负责释放已用资源,并且是
@BeforeClass
注释的对应项。


0
投票

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

public class TestClass {

    @Rule
    public SomeRule rule;

    public TestClass() {
        // code to initialize the rule field
        conf = new RuleConf()
        rule = new SomeRule(conf)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.