【问题标题】:When to use a unit test vs a BDD test何时使用单元测试与 BDD 测试
【发布时间】:2017-04-05 13:34:38
【问题描述】:

基于对 BDD 的一些简单阅读,我得出的结论是,单元测试是测试应用程序某些细粒度部分的好工具,而 BDD 是更高级别的,您可以在其中练习功能工作流。

我会考虑单元测试候选的一些项目:排序算法、状态缩减器、几何计算等......

我认为 BDD 候选人的项目将是功能工作流:将项目添加到购物车、登录、搜索网站内容以查找课程资料等...

一个客户要求我写一个排序算法,通常我会写一个单元测试,比如:

public class SorterTest
{
    [TestMethod]
    public void TestSort()
    {
        var numbers = new List<int>() { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
        var expected = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

        var sorter = new Sorter()
        {
            Input = numbers
        };

        var sorted = sorter.Sort();
        CollectionAssert.AreEqual(expected, sorted.ToList());
    }
}

但是,客户要求进行 BDD 测试,所以我想出了以下内容:

Feature: Sort
In order to to ensure sorting of integers
I want to be able to sort a collection of integers

Scenario Outline: Perform a sort
Given I have these integers: '<input>'
When I sort them
Then the result should be '<expected>'

Examples:
| input                           | expected          |
| 9,8,7,6,5,4,3,2,1               | 1,2,3,4,5,6,7,8,9 |

为了使我的 Sorter 对象可用于 BDD 测试,我必须对其进行更改:

    private Sorter sorter = new Sorter();
    [Given(@"^I have the following integers: '(.*)'$")]
    public void GivenIHaveTheFollowingIntegers(string numbers)
    {            
        var inputs = numbers.Split(',')
                            .Select(s => Convert.ToInt32(s.Trim()))
                            .ToList();
        sorter.Input = inputs;
    }

注意使用Given 设置测试,我必须将Input 属性添加到Sorter tp 为排序做准备。缺点是在应用程序代码中,如果我想让我的排序器执行排序,我总是需要在执行排序之前设置这个属性:

sorter.Input = intCollection;
var result = sorter.sort();

我宁愿只拥有:

var result = sorter.sort(intCollection);

BDD 适合这种测试吗?如果是这样,我做得对吗?添加Input 属性感觉不对,我应该用其他方式吗?

如果不合适,如何在 BDD 和单元测试之间划清界限?有一个existing SO post,但答案参考了一本书。如果能得到一些更好的指导,那就太好了。

【问题讨论】:

  • 关于作为属性的输入。这种设计有什么特殊原因吗?我宁愿提供 Input 作为 Sort 方法的参数。
  • @TheoLenndorff 这就是我帖子的关键——我必须添加一个Input 属性来设置Given 中的测试。我同意这感觉很尴尬,但我不知道我还能如何设置我的 BDD 测试。
  • 简而言之:行为测试在应用程序级别进行测试,单元测试在组件级别进行测试。您通常不会为排序方法编写行为测试;你会写行为测试,例如对于一个 UI 功能,它会测试整个应用程序堆栈(或至少到一些明确定义的边界)。
  • @Mister Epic:明白。我认为在When步骤中实例化被测系统(SUT)并没有错。在 Given 步骤中提供所有输入很重要。无需为了测试而强制生产代码进行奇怪的设计。
  • @Mister Epic:哦……我想我明白你的理由了。 Sorter 类应该设计为无状态的。恕我直言,在 When 步骤中实例化无状态类没有问题。如果它有意义并且该类具有某种状态,那么在您尝试过的 Given 步骤中实例化它可能会很有用。对于集成测试尤其如此。

标签: c# unit-testing automated-tests bdd


【解决方案1】:

在两种风格之间进行选择

在单元测试 (TDD) 方法和 BDD 方法之间进行选择归结为偏好。如果客户要求 BDD,请提供 BDD。如果团队更喜欢 TDD,请使用 TDD。

混合使用两种方法

选择不是唯一的。我有混合两种方法的经验。要回答在两种方法之间划清界限的问题,Agile Testing Quadrants 非常有帮助:

画一条线

我发现单元测试 (TDD) 方法对于面向技术的测试更有帮助。 BDD 方法对于面向业务的测试更有帮助。

有关此观察的详细信息

将业务需求映射到 BDD 样式测试更为自然。要测试具有某种触觉业务价值的业务需求,通常需要集成多个类。根据我的经验,那些 BDD 风格的测试通常是集成测试,并且具有功能测试用户接受度测试的特点。

另一方面,TDD 测试是由程序员为程序员编写的。许多程序员对单元测试 (TDD) 方法更熟悉或有更多经验。这些测试通常孤立地测试类,并强调系统的边缘情况和技术方面。

您提供的示例是一个例外,因为它将业务案例映射到单个类中。在这种情况下,两种方法都可以。

【讨论】:

    【解决方案2】:

    我会写一个单元测试。

    你提到了

    我会考虑单元测试候选的一些项目:排序算法、状态缩减器、几何计算等......

    我认为 BDD 候选人的项目将是功能工作流:将项目添加到购物车、登录、搜索网站内容以查找课程资料等...

    我同意这一点。行为驱动测试擅长快速“规范”并确保应用程序行为正确,并按预期行事。您可以采用这个定义并说您正在确保您的排序工作,但关键(IMO)是您不是在测试您的程序如何工作,而是算法如何工作,这是程序的一个非常具体的元素。如果你看看你是如何构建测试的,你会发现你正在尝试模仿一个单元测试:你抛出一堆输入,然后与你试图获得的输出进行比较。

    BDD 测试旨在以场景的形式测试功能。例如,如果您有一个程序从文件中组织电话号码,排序将是该过程的一部分,但您不涉及“排序”本身,您测试程序的一般行为(如果您获得执行应用程序产生的预期文件)。您设置测试,执行它,验证结果。

    您还应该在编写代码之前编写测试,我同意@Theo Lenndoff 的观点,将输入作为属性很奇怪而且非常违反直觉。 (你也提到过)。

    【讨论】:

      【解决方案3】:

      首先,我的经验是,在测试单元时,BDD 思维有时会有所帮助。

      其次,我认为“Given”关键字被滥用了。您能否要求您的客户将他们的场景重写为:

      Scenario Outline: Perform a sort
      When I sort these integers: '<input>'
      Then the result should be '<expected>'
      

      我发现 Given 的正确用法是用于必须存在于被测系统中的对象。在您的示例中,它被用于用户头脑中存在的某些东西:在代码中实现它必然是不自然的。

      第三,如果我必须实现“Given”子句,我会将整数列表存储在测试环境中,而不是尝试立即将它们插入应用程序。然后“When”步骤可以从测试环境中检索它们并在代码需要的地方使用它们。

      【讨论】:

        猜你喜欢
        • 2011-01-20
        • 2011-05-08
        • 1970-01-01
        • 2011-07-07
        • 2010-10-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多