我用的是JUnit 4。我看不出在构造函数中初始化和使用@Before注解的专用init函数之间的区别。是不是意味着我不用担心了?@Before在构造函数中给出的不仅仅是初始化,还有其他情况吗?
@Before
holgip5t1#
不,使用构造函数初始化JUnit测试夹具在技术上等同于使用@Before方法(因为JUnit为每个@Test创建了测试类的新示例)。唯一的(内涵上的)区别是它打破了@Before和@After之间的对称性,这可能会让一些人感到困惑。IMHO最好遵守约定(使用@Before)。还要注意的是,在JUnit 4和annotations之前,有专门的setUp()和tearDown()方法-@Before和@After annotations替换了这些方法,但保留了底层逻辑。因此,使用注解也使从JUnit 3或更早版本迁移的人更容易。
@Test
@After
setUp()
tearDown()
评论中的更多细节:
@Rule
gjmwrych2#
@Before在某些情况下使用更有意义,因为它在类的构造函数之后被调用。当您使用带有@Mock注解的Mockito这样的mock框架时,这种差异很重要,因为您的@Before方法将在mock初始化之后被调用。然后,您可以使用模拟为被测类提供构造函数参数。我发现在使用协作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)); } }
q9rjltbz3#
我更喜欢使用构造函数来初始化我的测试对象,因为它允许我将所有成员设置为final,以便IDE或编译器在 * 构造函数 * 忘记初始化成员时告诉我,并防止其他方法设置它们。恕我直言,@Before违反了最重要的Java约定之一,即依赖构造函数来完全初始化对象!JUnit 5对构造函数注入也有更好的支持。
final
vwhgwdsa4#
我更喜欢将fixture声明为final,并内联或在构造函数中初始化它们,这样我就不会忘记初始化它们!然而,由于在@Before中抛出的异常是以一种更用户友好的方式处理的,所以我通常在@Before中初始化测试对象。
lawou6xi5#
引用自http://etutorials.org/Programming/Java+extreme+programming/Chapter+4.+JUnit/4.6+Set+Up+and+Tear+Down/您可能想知道为什么要编写setUp()方法,而不是简单地在测试用例的构造函数中初始化字段。毕竟,由于测试用例的每个测试方法都创建了一个新的示例,所以构造函数总是在setUp()之前调用。在绝大多数情况下,您可以使用构造函数而不是setUp(),而不会产生任何副作用。在测试用例是更深层次继承层次结构的一部分的情况下,您可能希望推迟对象初始化,直到派生类的示例完全构造完成。这是一个很好的技术原因,说明为什么您可能希望使用setUp()而不是构造函数进行初始化。使用setUp()和tearDown()也有利于文档的目的,因为它可以使代码更容易阅读。
zengzsys6#
有一件事 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 } }
3gtaxfhh7#
@Before确实有意义,原因有几个。它使您的测试代码更具可读性。它匹配@After注解,@After注解负责释放已使用的资源,并且是@BeforeClass注解的对应物。
@BeforeClass
1szpjjfi8#
除了构造函数是ehere可以初始化@Rule对象的唯一方法之外,没有什么区别:
public class TestClass { @Rule public SomeRule rule; public TestClass() { // code to initialize the rule field conf = new RuleConf() rule = new SomeRule(conf) } }
8条答案
按热度按时间holgip5t1#
不,使用构造函数初始化JUnit测试夹具在技术上等同于使用
@Before
方法(因为JUnit为每个@Test
创建了测试类的新示例)。唯一的(内涵上的)区别是它打破了@Before
和@After
之间的对称性,这可能会让一些人感到困惑。IMHO最好遵守约定(使用@Before
)。还要注意的是,在JUnit 4和annotations之前,有专门的
setUp()
和tearDown()
方法-@Before
和@After
annotations替换了这些方法,但保留了底层逻辑。因此,使用注解也使从JUnit 3或更早版本迁移的人更容易。显著差异
评论中的更多细节:
@Before
允许重写父类行为,构造函数强制您调用父类构造函数@Rule
方法之前运行,@Before
在所有这些方法之后运行@Before
期间调用会导致调用@After
方法,但在构造函数中调用不会gjmwrych2#
@Before在某些情况下使用更有意义,因为它在类的构造函数之后被调用。当您使用带有@Mock注解的Mockito这样的mock框架时,这种差异很重要,因为您的@Before方法将在mock初始化之后被调用。然后,您可以使用模拟为被测类提供构造函数参数。
我发现在使用协作bean时,这是我的单元测试中非常常见的模式。
这里有一个(当然是人为的)例子:
q9rjltbz3#
我更喜欢使用构造函数来初始化我的测试对象,因为它允许我将所有成员设置为
final
,以便IDE或编译器在 * 构造函数 * 忘记初始化成员时告诉我,并防止其他方法设置它们。恕我直言,
@Before
违反了最重要的Java约定之一,即依赖构造函数来完全初始化对象!JUnit 5对构造函数注入也有更好的支持。
vwhgwdsa4#
我更喜欢将fixture声明为final,并内联或在构造函数中初始化它们,这样我就不会忘记初始化它们!然而,由于在@Before中抛出的异常是以一种更用户友好的方式处理的,所以我通常在@Before中初始化测试对象。
lawou6xi5#
引用自http://etutorials.org/Programming/Java+extreme+programming/Chapter+4.+JUnit/4.6+Set+Up+and+Tear+Down/
您可能想知道为什么要编写setUp()方法,而不是简单地在测试用例的构造函数中初始化字段。毕竟,由于测试用例的每个测试方法都创建了一个新的示例,所以构造函数总是在setUp()之前调用。在绝大多数情况下,您可以使用构造函数而不是setUp(),而不会产生任何副作用。
在测试用例是更深层次继承层次结构的一部分的情况下,您可能希望推迟对象初始化,直到派生类的示例完全构造完成。这是一个很好的技术原因,说明为什么您可能希望使用setUp()而不是构造函数进行初始化。使用setUp()和tearDown()也有利于文档的目的,因为它可以使代码更容易阅读。
zengzsys6#
有一件事 constructor 可以存档,但 @Before 不能。
当你需要初始化父类中定义的字段时,你必须使用构造函数。举例来说:
3gtaxfhh7#
@Before
确实有意义,原因有几个。它使您的测试代码更具可读性。它匹配@After
注解,@After
注解负责释放已使用的资源,并且是@BeforeClass
注解的对应物。1szpjjfi8#
除了构造函数是ehere可以初始化@Rule对象的唯一方法之外,没有什么区别: