问题

我应该在这样的声明中初始化类字段吗?

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
    }
}

或者像setUp()这样?

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将根据每种测试方法实例化一次测试类。这意味着每次测试都会创建list,无论我在哪里声明它。这也意味着测试之间没有时间依赖关系。因此,使用setUp()似乎没有任何优势。但是JUnit FAQ有很多例子可以在setUp()中初始化一个空集合,所以我认为必须有一个原因。


#1 热门回答(86 赞)

如果你特别想知道JUnit常见问题解答中的例子,例如basic test template,我认为最好的做法是在测试中的类应该在你的setUp方法(或测试方法)中实例化。

当JUnit示例在setUp方法中创建一个ArrayList时,它们都会继续测试该ArrayList的行为,例如testIndexOutOfBoundException,testEmptyCollection等。有人写一个班级并确保它正常运作。

在测试自己的类时,你可能应该这样做:在setUp或测试方法中创建对象,这样如果以后打破它,你将能够获得合理的输出。

另一方面,如果你在测试代码中使用Java集合类(或其他类库),那可能不是因为你想要测试它 - 它只是测试夹具的一部分。在这种情况下,你可以安全地假设它按预期工作,因此在声明中初始化它不会有问题。

为了它的价值,我在一个相当大,几年,TDD开发的代码库上工作。我们习惯性地在测试代码的声明中初始化事物,并且在我参与这个项目的一年半中,它从未引起过任何问题。所以至少有一些轶事证据表明它是合理的。


#2 热门回答(41 赞)

我开始挖掘自己,我找到了使用setUp()的一个潜在优势。如果在执行setUp()期间抛出任何异常,JUnit将打印一个非常有用的堆栈跟踪。另一方面,如果在对象构造期间抛出异常,则错误消息只是说JUnit无法实例化测试用例,并且你没有看到发生故障的行号,可能是因为JUnit使用反射来实例化测试类。

这些都不适用于创建空集合的示例,因为它永远不会抛出,但它是setUp()方法的优势。


#3 热门回答(17 赞)

除了Alex B的回答。

甚至需要使用setUp方法来实例化某种状态的资源。在构造函数中执行此操作不仅是时间问题,而且由于JUnit运行测试的方式,每个测试状态将在运行一个后被擦除。

JUnit首先为每个测试方法创建testClass的实例,并在创建每个实例后开始运行测试。在运行测试方法之前,运行其设置方法,其中可以准备一些状态。

如果将在构造函数中创建数据库状态,则在运行每个测试之前,所有实例都会在彼此之后立即实例化db状态。从第二次测试开始,测试将以脏状态运行。

JUnits生命周期:

  • 为每个测试方法创建不同的testclass实例
  • 对每个testclass实例重复:call setup调用testmethod

在测试中使用两种测试方法进行一些记录:(number是哈希码)

  • 创建新实例:5718203
  • 创建新实例:5947506
  • 设置:5718203
  • TestOne:5718203
  • 设置:5947506
  • TestTwo:5947506

原文链接