单元测试写作的最佳实践

时间:2011-01-21 15:54:37

标签: unit-testing automated-tests

我有一个“最佳做法”问题。我正在为某个方法编写测试,但是有多个条目值。我应该为每个条目值编写一个测试,还是应该更改entryValues变量值,并调用.assert()方法(对所有可能的值执行此操作)?

感谢您的帮助。 最好的问候,

Pedro Magueija

编辑:我正在使用.NET。 Visual Studio 2010 with VB。

6 个答案:

答案 0 :(得分:5)

如果必须编写许多仅在初始输入和最终输出中变化的测试,则应使用数据驱动测试。这允许您定义测试一次以及输入和输出之间的映射。然后,单元测试框架将其解释为每个案例的一个测试。如何实际执行此操作取决于您使用的是哪个框架。

答案 1 :(得分:2)

最好对每个输入/输出集进行单独的单元测试,覆盖您尝试测试的方法的全部可能值(或者至少对于您要进行单元测试的输入/输出集)。 / p>

答案 2 :(得分:1)

  1. 较小的测试更容易阅读。
  2. 该名称是测试文档的一部分。
  3. 单独的方法可以更精确地指示失败的原因。
  4. 所以,如果您有一个方法,如:

    void testAll() {
      // setup1
      assert()
      // setup2
      assert()
      // setup3
      assert()
    }
    

    根据我的经验,这会变得非常快,因此变得难以阅读和理解,所以我会这样做:

    void testDivideByZero() {
      // setup
      assert()
    }
    
    void testUnderflow() {
      // setup
      assert()
    }
    
    
    void testOverflow() {
      // setup
      assert()
    }
    

答案 3 :(得分:1)

  

我应该为每个条目写一个测试   价值还是应该改变   entryValues变量值,并调用   .assert()方法(为所有人做   范围可能的值)?

如果您通常有一个代码路径,则不会测试所有可能的输入。你通常想要测试的是“有趣”的输入,这些输入可以很好地得到你将获得的数据。

例如,如果我有一个功能

define add_one(num) {
  return num+1;
}

我无法为所有可能的值编写测试,因此我可以使用MAX_NEGATIVE_INT,-1,0,1,MAX_POSITIVE_INT作为我的测试集,因为它们是我可能获得的有趣值的良好代表。

每个代码路径至少应有一个输入。如果你有一个函数,其中每个值对应一个唯一的代码路径,那么我会考虑为整个可能的值范围编写测试。例如,这将是一个命令解析器。

define execute(directive) {
  if (directive == 'quit') { exit; }
  elsif (directive == 'help') { print help; }
  elsif (directive == 'connect') { intialize_connection(); }
  else { warn("unknown directive"); }
}

为了清楚起见,我使用了elif而不是调度表。我认为这清楚地表明,每个独特的值都有不同的行为,因此您需要测试每个可能的值。

答案 4 :(得分:0)

你在谈论这种差异吗?

- (void) testSomething
{
    [foo callBarWithValue:x];
    assert…
}

- (void) testSomething2
{
    [foo callBarWithValue:y];
    assert…
}

VS

- (void) testSomething
{
    [foo callBarWithValue:x];
    assert…
    [foo callBarWithValue:y];
    assert…
}

第一个版本更好,因为当测试失败时,您将更好地了解哪些不起作用。第二个版本显然更方便。有时我甚至会将测试值填入集合中以节省工作量。我通常会选择第一种方法,因为我可能只想单独调试这个案例。当然,我只选择后者,当测试值真正属于一起并形成一个连贯的单位时。

答案 5 :(得分:0)

你真的有两种选择,你没有提到你使用的测试框架或语言,因此可能不适用。

1)如果你的测试框架支持它使用RowTest,MBUnit和Nunit支持这个,如果你使用.NET这将允许你在你的方法上放置多个属性,每一行将作为一个单独的测试执行

2)如果没有为每个条件编写一个测试,并确保给它一个有意义的名称,这样如果(当)测试失败,你可以很容易地找到问题,这对你意味着什么。

修改  它在Nunit中称为TestCase Nunit TestCase Explination