Java 最佳实践:在setUp()或声明中初始化JUnit类字段?
我应该像这样在声明中初始化类字段吗Java 最佳实践:在setUp()或声明中初始化JUnit类字段?,java,junit,Java,Junit,我应该像这样在声明中初始化类字段吗 public class SomeTest extends TestCase { private final List list = new ArrayList(); public void testPopulateList() { // Add stuff to the list // Assert the list contains what I expect } } public cla
public class SomeTest extends TestCase
{
private final List list = new ArrayList();
public void testPopulateList()
{
// Add stuff to the list
// Assert the list contains what I expect
}
}
public class SomeTest extends TestCase
{
private List list;
@Override
protected void setUp() throws Exception
{
super.setUp();
this.list = new ArrayList();
}
public void testPopulateList()
{
// Add stuff to the list
// Assert the list contains what I expect
}
}
还是像这样在setUp()中
public class SomeTest extends TestCase
{
private final List list = new ArrayList();
public void testPopulateList()
{
// Add stuff to the list
// Assert the list contains what I expect
}
}
public class SomeTest extends TestCase
{
private List list;
@Override
protected void setUp() throws Exception
{
super.setUp();
this.list = new ArrayList();
}
public void testPopulateList()
{
// Add stuff to the list
// Assert the list contains what I expect
}
}
我倾向于使用第一个表单,因为它更简洁,并且允许我使用最终字段。如果我不需要使用setUp()方法进行设置,我还应该使用它吗?为什么
澄清:
JUnit将为每个测试方法实例化一次测试类。这意味着无论我在哪里声明,每个测试都将创建一次
列表。这也意味着测试之间没有时间依赖关系。因此,使用setUp()似乎没有任何好处。然而,JUnit FAQ中有许多在setUp()中初始化空集合的示例,因此我认为这一定是有原因的。我更喜欢可读性第一,这通常不使用setUp方法。当基本设置操作需要很长时间并且在每次测试中重复时,我会例外。
此时,我使用@BeforeClass
注释(稍后优化)将该功能移动到设置方法中
使用@BeforeClass
设置方法进行优化的示例:我使用dbunit进行一些数据库功能测试。安装方法负责将数据库置于已知状态(非常慢…30秒-2分钟,取决于数据量)。我在用@BeforeClass
注释的setup方法中加载此数据,然后对同一组数据运行10-20个测试,而不是在每个测试中重新加载/初始化数据库
使用Junit 3.8(如您的示例所示扩展TestCase)需要编写比添加注释多一点的代码,但是“在类设置之前运行一次”仍然是可能的。除了Alex B的答案之外
甚至需要使用setUp方法来实例化处于特定状态的资源。在构造函数中执行此操作不仅是时间问题,而且由于JUnit运行测试的方式,每个测试状态在运行一个测试状态后都会被擦除
JUnit首先为每个测试方法创建testClass的实例,并在创建每个实例后开始运行测试。在运行测试方法之前,将运行其设置方法,在此方法中可以准备一些状态
如果数据库状态是在构造函数中创建的,那么所有实例都会在运行每个测试之前,依次实例化数据库状态。从第二个测试开始,测试将以脏状态运行
JUnits生命周期:
为每个测试方法创建不同的testclass实例
对每个testclass实例重复:调用setup+调用testmethod
使用两种测试方法在测试中进行一些日志记录,您可以得到:(数字是哈希代码)
- 创建新实例:571823
- 正在创建新实例:5947506
- 设置:571823
- 测试一:571823
- 设置:5947506
- 测试二:5947506
我开始挖掘自己,发现使用setUp()
的一个潜在优势。如果在执行setUp()
期间抛出任何异常,JUnit将打印非常有用的堆栈跟踪。另一方面,如果在对象构造过程中抛出异常,错误消息只是说JUnit无法实例化测试用例,并且您看不到发生故障的行号,可能是因为JUnit使用反射来实例化测试类
所有这些都不适用于创建空集合的示例,因为这永远不会抛出,但这是setUp()
方法的一个优点。在您的情况下(创建列表),实践中没有区别。但通常最好使用setUp(),因为这将有助于Junit正确报告异常。如果测试的构造函数/初始值设定项中发生异常,则表示测试失败。但是,如果在安装过程中发生异常,自然会将其视为设置测试时的一些问题,junit会适当地报告它。由于每个测试都是独立执行的,并且有一个新的对象实例,因此测试对象除了在setup()之间共享的状态外,没有任何内部状态的意义
和一个单独的测试和拆卸()。这是使用setUp()
方法很好的一个原因(除了其他人给出的原因)
注意:JUnit测试对象保持静态是个坏主意!如果在测试中使用静态变量不是为了跟踪或诊断,那么JUnit的部分目的就是无效的,即测试可以(可能)以任何顺序运行,每个测试都以全新的干净状态运行
使用setUp()
的优点是,您不必在每个测试方法中剪切和粘贴初始化代码,并且在构造函数中也不需要测试设置代码。在你的情况下,没有什么不同。只要创建一个空列表就可以安全地完成,正如您所显示的那样,或者在构造函数中,因为这是一个微不足道的初始化。但是,正如您和其他人所指出的,任何可能引发异常的操作都应该在setUp()
中完成,因此如果失败,您将获得诊断堆栈转储
在您的情况下,如果您只是创建一个空列表,我将按照您建议的方式执行:在声明点分配新列表。特别是因为这样,如果这对您的测试类有意义,您可以选择将其标记为final
。如果您特别想了解JUnit FAQ中的示例,例如,我认为这里展示的最佳实践是,应该在您的设置方法中实例化被测试的类(或在试验方法中)
当JUnit示例在setUp方法中创建ArrayList时,它们都会继续测试该ArrayList的行为,例如testIndexOutOfBoundEx