65.9K
CodeProject 正在变化。 阅读更多。
Home

SpecFlow 的强大之处

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2020 年 5 月 22 日

CPOL

2分钟阅读

viewsIcon

9724

SpecFlow 简介

引言

编写测试可能很枯燥,并且利益相关者可能知道您的软件应该如何运行。

SpecFlow 可以帮助您。它是一个用于 BDD 的框架,使用 Visual Studio 的扩展,将用户请求的功能转换为测试代码。

SpecFlow 允许您用自己的语言编写行为,并以类似于 Excel 表格的形式显示数据。

安装 SpecFlow

您需要在测试项目中安装 Visual Studio 的扩展。安装此包,nuget SpecFlow, SpecFlow.Tools.MsBuild.Generation,它将从我们的 IDE 生成代码,以及 SpecFlow.xUnit(如果您使用 xUnit),它将允许 Visual Studio 找到 SpecFlow 将自动生成的测试。

背景

假设您想为具有在线购买功能的果蔬仓库创建测试。

但是,请注意正确划分章节,而这正是我想要重点讨论的。

背景 (Background) 部分用于收集所有在每个测试场景中都通用的信息。例如,用户列表。

Feature: Order and warehouse testing
Background 
Given registered users 
| UserId   | Name  | Surname | Mail             | Delivery address | City     |
| AJ       | John  | Red     | j.red@red.com    | Down street      | London   |
| MWitch   | Marck | Witch   | Mark.Witch@gl.it | High street      | New york | 

如果过于详细,背景部分可能会变得太大,您只需要编写需要在多个场景中使用的内容。

我们可以添加一个 @tag,它允许我们将功能收集起来,就像它们在一个命名空间中一样。

@Orders
Scenario: An order is submitted 

给定 (Given)、当 (When)、那么 (Then)

给定 (Given):描述我们想要测试的操作的前提条件

Given The warehouse
| Code | Products | Quantity | Unit of measure | Alert threshold |
| P1   | Tomato   | 150      | Box             | 25              |
| V1   | Wine     | 350      | Bottle          | 40              |

当 (When):放置触发我们想要测试的代码片段的操作

When An order arrives
| User | Product | Quantity |
| AJ   | P1      | 2        |
| AJ   | V1      | 1        |

那么 (Then):放置代码运行后需要发生的所有事情

Then The warehouse contains these products
| Code | Product  | Quantity |
| P1   | Tomato   | 148      |
| V1   | Wine     | 349      |

Then the Purchasing Office is notified
| Product under threshold | Quantity | Threshold |

或者另一个场景

@Order
Scenario: An order is placed that lowers the quantity of the products under the threshold
Given The warehouse
| Code | Products | Quantity | Unit of measure | Alert threshold |
| P1   | Tomato   | 26       | Box             | 25              |
| V1   | Wine     | 350      | Bottle          | 40              |

When An order arrives
| Users| Products | Quantity |
| AJ   | P1       | 2        |
| AJ   | V1       | 1        |

Then The warehouse contains these products
| Code | Products | Quantity |
| P1   | Tomato   | 24       |
| V1   | Wine     | 349      |

Then the Purchasing Office is notified
| Products under threshold | Quantity | Threshold |
| P1                       | 24       | 25        |

代码

现在,您需要将表格绑定到一段代码。

在这里,SpecFlow 为 Visual Studio 的扩展发挥作用,它将我们输入的 GivenWhenThen 转换为方法。右键单击 specflow 文件,选择“生成步骤定义 (Generate Step Definition)”。

您需要使用它来保存明显是虚构的数据,使用内存数据库,该数据库将在您的 Given 中填充数据。

[Given(@"registered users")]
public void GivenregisteredUsers(Table table) {
    foreach (var row in table.Rows)
    {
        sessionManager.AddRecord(
            new User
            {
                UserId = row["UserId"],
                Name = row["Name"],
                Surname = row["Surname"],
                DeliveryCity = row["City"],
                DeliveryAddress = row["Delivery address"],
                Mail = row["Mail"]
            });
        }
    }
}

When 将响应一段代码,该代码将调用我们用于下订单的方法

[When(@"An order arrives")]
public void WhenAnOrderArrives(Table table)
{
    OrderCore core = new OrderCore(sessionManager);
    List<<order>order> = new <List><order>();
    foreach (var row in table.Rows)
    {
        order.Add(
            new Order
            {
                User = row["User"],
                Product = row["Products"],
                Quantity = Convert.ToDecimal(row["Quantity"]),
            });
    }
    result = core.AcceptOrder(order);
}

使用代码

public OrderResult AcceptOrder(IEnumerable<order> orders)
{
    var orderResult = new OrderResult();
    foreach (var order in orders)
    {
        var product = sessionManager.Query<product>()
            .Single(x => x.Code == order.Product);
        
        product.Quantity = product.Quantity - order.Quantity;
        sessionManager.SaveOrUpdate(product);

        if (product.Quantity < product.Threshold)
            orderResult.AlertThresholds.Add(
                new OrderResult.AlertThreshold
                {
                    product = product.Name,
                    Quantity = product.Quantity,
                    Threshold = product.Threshold
                });
    }

    return orderResult;
}

Then 中,我们将放置一些代码,该代码将检查是否产生了期望的行为。

[Then(@"The warehouse contains these products")]
public void ThenTheWarehouseContainsTheseProducts(Table table)
{
    var products = sessionManager.Query<Product>();
    foreach (var row in table.Rows)
    {
        var product = products.Where(x => x.Code == row["Code"]).Single();
        Assert.That(product.Quantity == Convert.ToDecimal(row["Quantity"]));
    }
}

[Then(@"the Purchasing Office is notified")]
public void ThenThePurchasingOfficeIsNotified(Table table)
{
    if (table.Rows.Count == 0)
        Assert.That(result.AlertThresholds.Count() == 0);
    else
    {
        Assert.That(result.AlertThresholds.Count() == table.Rows.Count);
        foreach (var row in table.Rows)
        {
            var product = result.AlertThresholds
                .SingleOrDefault(x => x.product == row["Products under threshold"]);

            Assert.That(product != null);
            Assert.That(product.Quantity == Convert.ToDecimal(row["Quantity"]));
            Assert.That(product.Threshold == Convert.ToDecimal(row["Threshold"]));
        }
    }
}

构建解决方案时,Visual Studio 将找到测试并在测试资源管理器中显示它们,您可以在其中运行测试。

示例代码位于 GitHub 上。

历史

  • 2020 年 5 月 22 日:初始版本
© . All rights reserved.