@Before
注解的init函数之间有什么区别。这是否意味着我不必担心它?是否有任何情况下
@Before
比仅在构造函数中进行初始化更有用?@Before
注解的init函数之间有什么区别。这是否意味着我不必担心它?@Before
比仅在构造函数中进行初始化更有用?不,使用构造函数来初始化JUnit测试夹具在技术上等同于使用@Before
方法(因为JUnit为每个@Test
创建了测试类的新实例)。唯一的(内涵)差异是它破坏了@Before
和@After
之间的对称性,这可能会让一些人感到困惑。在我看来,最好遵循约定(即使用@Before
)。
还要注意,在JUnit 4和注释之前,有专用的setUp()
和tearDown()
方法- @Before
和@After
注释替换了这些方法,但保留了底层逻辑。因此,对于从JUnit 3或更早版本迁移的人来说,使用注释也会使生活更轻松。
下面是从评论中得到的更多细节:
@Before
允许覆盖父类行为,构造函数则强制您调用父类构造函数@Rule
方法之前运行,@Before
在所有这些方法之后运行@Before
中的异常会导致调用@After
方法,构造函数中的异常则不会@Before
方法被调用的次数完全相同。 - Péter Török@After
。因此,我仍然使用注解,并仅保留最小的构造函数。 - vbence[SetUp]
方法(NUnit中与@Before
相当)实际上会导致错误。对我来说,这就像“依赖于接口,而不是实现”的格言一样,在长期维护中使代码更具可移植性和易于维护。 - Péter Török@Before
是一个好主意,尽管当使用@Before
时,我无法使我的数据成员引用最终化,这让我感到困扰。 - Derek Mahar@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));
}
}
我更喜欢使用构造函数来初始化我的测试对象,因为这样可以使所有成员变量都是final
,这样IDE或编译器会在构造函数忘记初始化某个成员变量时告诉我,并防止另一个方法设置它们。
依我之见,@Before
违反了最重要的Java约定之一,即依赖构造函数完全初始化对象!
JUnit 5也对构造函数注入提供了更好的支持。
我更喜欢将我的固定装置声明为final,并在内联或构造函数中初始化它们,这样我就不会忘记初始化它们!然而,由于@Before中抛出的异常以更用户友好的方式处理,我通常会在@Before中初始化被测试对象。
你可能会想知道为什么要编写setUp()方法而不是只在测试用例的构造函数中初始化字段。毕竟,对于每个测试方法,都会创建该测试用例的新实例,因此构造函数总是在setUp()之前被调用。在绝大多数情况下,您可以使用构造函数代替setUp()而没有任何副作用。
在您的测试用例是更深层次继承关系的一部分时,您可能希望推迟对象初始化直到派生类的实例完全构建。这是一个很好的技术原因,您可能希望使用setUp()而不是构造函数进行初始化。使用setUp()和tearDown()还有助于文档编写,因为它可以使代码更易于阅读。
有一件事情是构造函数可以实现但@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
}
}
除了构造函数是唯一可以初始化@Rule对象的方法外,没有任何区别:
public class TestClass {
@Rule
public SomeRule rule;
public TestClass() {
// code to initialize the rule field
conf = new RuleConf()
rule = new SomeRule(conf)
}
}
@Before
有很多使用的理由。它可以使你的测试代码更易读。它与 @After
注解相匹配,后者负责释放已使用的资源,并是 @BeforeClass
注解的对应项。
@Before
,而不是@BeforeClass
吗?在这里查看它们的区别:https://dev59.com/mWIj5IYBdhLWcg3waEZe。 - Line