【问题标题】:BDD 'Given' step description and implementationBDD 'Given' 步骤描述和实现
【发布时间】:2011-11-25 10:36:44
【问题描述】:

您通常如何描述和实施场景的“给定”步骤?

  1. 高级状态描述或显式数据定义?
  2. 填充数据库或存根存储库?

高级状态描述

Given I have 4 products
When I look for best-selling products
Then I see top 3 products with maximum number of sales

专业版

  • 不脆
  • 易于阅读和理解业务目标

缺点

  • 不清楚我们需要什么数据

显式数据定义

Given I have following products:
  | Name         | Sales number    |
  | Beer         | 20              |
  | Pizza        | 5               |
  | Socks        | 3               |      
  | Toilet paper | 100             |
When I look for best-selling products
Then I see following products:
  | Name         | Sales number    |
  | Toilet paper | 100             |
  | Beer         | 20              |
  | Pizza        | 5               |

专业版

  • 易于实施(明确需要哪些数据)

缺点

  • 难以阅读和理解业务目标
  • 更脆

填写数据库

using (var connection = new SqlConnection(connectionString))
{                
    using (var deleteCommand = new SqlCommand("DELETE FROM Products", connection))
    {
        connection.Open();
        deleteCommand.ExecuteNonQuery();
    }

    SqlDataAdapter adapter = new SqlDataAdapter("SELECT * FROM Products", connection);              
    DataSet data = new DataSet();
    adapter.Fill(data);

    foreach (var specFlowRow in table.Rows)
    {
        DataRow dataRow = data.Tables[0].Rows.Add();
        dataRow["Name"] = specFlowRow["Name"];                   
    }

    adapter.Update(data);
}

专业版

  • 作为集成测试的规范(我们使用端到端系统)

缺点

  • 我们需要在代码之前创建数据库表(数据驱动的方法)
  • 易碎
  • 难以实施

存储库存根

// or get stubbed repository from DI framework
productsRepository = new InMemoryProductsRepository();            

// or use specflow assist helpers
foreach (var specFlowRow in table.Rows)            
    productsRepository.Save(new Product(specFlowRow["Name"]));

专业版

  • 我们可以先做代码
  • 快速
  • 不易碎(易于更换)
  • 易于实施

缺点

  • 我们没有证据表明功能已实现

这就是我对可能方式的看法 :) 您以什么方式定义和实施“给定”步骤? 谢谢!

【问题讨论】:

    标签: c# tdd integration-testing bdd specflow


    【解决方案1】:

    我们通过您提到的组合实现 Given。通过使用 DI 和不同的配置(使用 this tool 轻松实现),我们大部分时间在内存中运行我们的单元测试,并在 CI 服务器上强制它们一次作为针对真实数据库的集成测试。因此,您可以获得性能和全面的测试。

    对于设置您的数据,我个人最喜欢您的示例“显式数据定义”。指定测试使用的数据确保您可以将测试作为文档阅读。针对未知数据存储运行会使测试难以阅读。但是在这种情况下构建您的测试数据时,产品的名称并不重要,重要的是数量。

    这是通过使用 Builder 模式来处理的。仅指定为您的测试导入的数据,并让 Builder 为所有其他字段生成默认值。

    NBuilder 是一个非常好的工具。我们现在正在使用它进行测试,它看起来很有希望。

    您的测试将如下所示:

    class Product
    {
        public string Name { get; set; }
        public int Sales { get; set; }
    }
    
    [TestMethod]
    public void SalesTest()
    {
        var products = Builder<Product>.CreateListOfSize(4)
             .TheFirst(1)
             .With(x => x.Sales = 20)
             .AndTheNext(1)
             .With(x => x.Sales = 5)
             .AndTheNext(1)
             .With(x => x.Sales = 3)
             .AndTheNext(1)
             .With(x => x.Sales = 100).Persist();
    
        var result = SystemUnderTest.Execute();
    
        Assert.AreEqual(3, result.Count);
    
        Assert.AreEqual(100, result[0].Sales);
        Assert.AreEqual(20, result[0].Sales);
        Assert.AreEqual(5, result[0].Sales);
    }
    

    【讨论】:

    • 感谢 SlowCheetah 的链接!使用内存存储库驱动开发是个好主意,然后在发布配置中全部切换到真实数据库。 NBuilder 看起来还不是很酷。似乎可以直接通过存储库完成设置。
    • “设置可以直接通过存储库完成”是什么意思?
    • 我的意思是我们可以使用带有简单内存收集的存根。我们可以通过调用 repository.Create(new Product("Apple", 10)) 在 Given 步骤填充存储库。好吧,在进一步研究了 NBuilder 之后,我看到我们可以定义 Create 方法以在 Persist() 上调用。
    • 是的。 persist 方法映射到您指定的函数。我们的上下文中有一个通用的 AddObject(假的和 EF 的),我们用于所有实体。
    【解决方案2】:

    作为对“我们如何为复杂或相关对象设置 Given?”的广泛回答。问题——比如产品和销售——这一切都取决于您指定的行为。没有唯一正确的方法。顺便说一句,您没有包含 Feature 和 Scenario 文本来为我们提供有关此 cuke 的行为的一些背景信息,但是,诚然,不难猜测。

    您的“不脆弱”的第一个示例展示了一种消除基本行为的好方法,即告诉我用户可以看到最畅销产品的简短列表及其销售数字。

    如果您想证明显示器以某种方式关心以排序方式显示事物,请更明确地给出,然后清楚地表明您是按销量“反向排序”。或者,可以认为这个明确的示例非常清楚您的意思。

    我通常的经验法则是将设置限制在您希望在当前场景中测试的“对象图”的那些部分。这有助于将注意力吸引到正在测试的系统中最“狭窄”的部分。否则,如果您继续为所有场景从头开始构建所有内容,有时很难看出测试的目的。有时您关心父对象中的细节,有时您想测试各部分的总和。

    【讨论】:

    • 感谢乔恩的回答!你能举一些这样的系统缩小的例子吗?提前致谢!
    • 我在使用 Cucumber 的 BDD 技术债务博客页面上添加了“缩小”部分:technicaldebt.com/?page_id=1341
    猜你喜欢
    • 1970-01-01
    • 2022-09-27
    • 1970-01-01
    • 1970-01-01
    • 2020-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-13
    相关资源
    最近更新 更多