何时使用单元测试与 BDD 测试
When to use a unit test vs a BDD test
基于对 BDD 的一些简单阅读,我得出结论,单元测试是测试应用程序某些细粒度部分的好工具,而 BDD 是更高级别的,您可以在其中练习功能工作流。
我会考虑作为单元测试候选人的一些项目:排序算法、状态缩减器、几何计算等...
我认为 BDD 候选人的项目将是功能工作流程:将项目添加到购物车、登录、搜索网站内容以查找课程 material 等...
我被客户要求写一个排序算法,通常我会写一个单元测试,比如:
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,但答案参考了一本书。如果能得到更好的指导就好了。
我会写一个单元测试。
你提到了
Some of the items I would consider candidates for unit tests: sorting algorithms, state reducers, geometric calculations, etc...
Items I would consider candidates for BDD would be feature workflows: adding an item to a cart, logging in, searching the contents of a site to find course material, etc...
我同意这一点。行为驱动测试擅长快速“规范”并确保应用程序 行为 正确,并按照预期进行。你可以采用这个定义并说你正在确保你的排序有效,但关键 (IMO) 是你不是在测试你的程序如何工作,而是在测试算法如何工作,这是程序的一个非常具体的元素。如果您查看构建测试的方式,您会发现您正在尝试模仿单元测试:您抛出一堆输入,然后与您尝试获得的输出进行比较。
BDD 测试旨在测试一个功能,如场景。例如,如果您有一个从文件中组织 phone 数字的程序,排序将是该过程的一部分,但您不单独介绍“排序”,而是测试程序的一般行为(如果您获得了执行应用程序所产生的预期文件)。您设置测试,执行它,验证结果。
您还应该在编写代码之前编写测试,我同意@Theo Lenndoff 的观点,将输入作为 属性 很奇怪而且非常违反直觉。 (你也提到了)。
两种风格选择
单元测试 (TDD) 方法和 BDD 方法之间的选择归结为偏好。如果客户要求 BDD,请提供 BDD。如果团队更习惯 TDD,请使用 TDD。
混合两种方法
选择不排他。我有混合使用这两种方法的经验。要回答在两种方法之间划清界线的问题,Agile Testing Quadrants 非常有帮助:
画线
我发现单元测试 (TDD) 方法对 面向测试的技术 更有帮助。 BDD 方法对 面向业务的测试更有帮助。
有关此观察的详细信息
将业务需求映射到 BDD 样式测试更为自然。要测试具有一定商业价值的业务需求,通常需要集成多个 classes。根据我的经验,那些 BDD 风格的测试通常是集成测试,并且具有 功能测试 和 用户验收测试 .
的特征
另一方面,TDD 测试是由程序员为程序员编写的。许多程序员对单元测试 (TDD) 方法更熟悉或更有经验。这些测试通常 classes 单独测试 并且强调系统的边缘情况和技术方面。
您提供的示例非常例外,因为它在单个 class 中映射了一个业务案例。在这种情况下,两种方法都可以。
首先,我的经验是 BDD 思维在测试单元时有时会有所帮助。
其次,我认为“Given”关键字被滥用了。您能否要求您的客户将他们的场景重写为:
Scenario Outline: Perform a sort
When I sort these integers: '<input>'
Then the result should be '<expected>'
我发现 Given 的正确用法是针对必须存在于被测系统中的对象。在您的示例中,它被用于用户头脑中存在的东西:在代码中实现它必然是不自然的。
第三,如果我必须实施“给定”子句,我会将整数列表存储在测试环境中,而不是尝试立即将它们插入到应用程序中。然后“When”步骤可以从测试环境中检索它们并在代码需要它们的地方使用它们。
基于对 BDD 的一些简单阅读,我得出结论,单元测试是测试应用程序某些细粒度部分的好工具,而 BDD 是更高级别的,您可以在其中练习功能工作流。
我会考虑作为单元测试候选人的一些项目:排序算法、状态缩减器、几何计算等...
我认为 BDD 候选人的项目将是功能工作流程:将项目添加到购物车、登录、搜索网站内容以查找课程 material 等...
我被客户要求写一个排序算法,通常我会写一个单元测试,比如:
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,但答案参考了一本书。如果能得到更好的指导就好了。
我会写一个单元测试。
你提到了
Some of the items I would consider candidates for unit tests: sorting algorithms, state reducers, geometric calculations, etc...
Items I would consider candidates for BDD would be feature workflows: adding an item to a cart, logging in, searching the contents of a site to find course material, etc...
我同意这一点。行为驱动测试擅长快速“规范”并确保应用程序 行为 正确,并按照预期进行。你可以采用这个定义并说你正在确保你的排序有效,但关键 (IMO) 是你不是在测试你的程序如何工作,而是在测试算法如何工作,这是程序的一个非常具体的元素。如果您查看构建测试的方式,您会发现您正在尝试模仿单元测试:您抛出一堆输入,然后与您尝试获得的输出进行比较。
BDD 测试旨在测试一个功能,如场景。例如,如果您有一个从文件中组织 phone 数字的程序,排序将是该过程的一部分,但您不单独介绍“排序”,而是测试程序的一般行为(如果您获得了执行应用程序所产生的预期文件)。您设置测试,执行它,验证结果。
您还应该在编写代码之前编写测试,我同意@Theo Lenndoff 的观点,将输入作为 属性 很奇怪而且非常违反直觉。 (你也提到了)。
两种风格选择
单元测试 (TDD) 方法和 BDD 方法之间的选择归结为偏好。如果客户要求 BDD,请提供 BDD。如果团队更习惯 TDD,请使用 TDD。
混合两种方法
选择不排他。我有混合使用这两种方法的经验。要回答在两种方法之间划清界线的问题,Agile Testing Quadrants 非常有帮助:
画线
我发现单元测试 (TDD) 方法对 面向测试的技术 更有帮助。 BDD 方法对 面向业务的测试更有帮助。
有关此观察的详细信息
将业务需求映射到 BDD 样式测试更为自然。要测试具有一定商业价值的业务需求,通常需要集成多个 classes。根据我的经验,那些 BDD 风格的测试通常是集成测试,并且具有 功能测试 和 用户验收测试 .
的特征另一方面,TDD 测试是由程序员为程序员编写的。许多程序员对单元测试 (TDD) 方法更熟悉或更有经验。这些测试通常 classes 单独测试 并且强调系统的边缘情况和技术方面。
您提供的示例非常例外,因为它在单个 class 中映射了一个业务案例。在这种情况下,两种方法都可以。
首先,我的经验是 BDD 思维在测试单元时有时会有所帮助。
其次,我认为“Given”关键字被滥用了。您能否要求您的客户将他们的场景重写为:
Scenario Outline: Perform a sort
When I sort these integers: '<input>'
Then the result should be '<expected>'
我发现 Given 的正确用法是针对必须存在于被测系统中的对象。在您的示例中,它被用于用户头脑中存在的东西:在代码中实现它必然是不自然的。
第三,如果我必须实施“给定”子句,我会将整数列表存储在测试环境中,而不是尝试立即将它们插入到应用程序中。然后“When”步骤可以从测试环境中检索它们并在代码需要它们的地方使用它们。