在Specflow中我可以运行一个测试作为另一个测试的一个步骤吗?

时间:2015-03-17 22:01:02

标签: c# unit-testing automated-tests dry specflow

TL; DR;如何创建一个将另一个测试作为第一步调用的specflow测试?

Given I already have one specflow test
And I want to run another test that goes deeper than the first test  
Then I create a second test that runs the first test as its first step
And I add additional steps to test the deeper functionality

对不起,那里有一点点幽默的幽默。

例如,我有一项测试已经开始销售:

Given I want to create a sales order
And I open the sales order page
And I click the add new order button
Then a new sales order is created

我希望有另一项测试来测试添加销售线

另一项测试完成销售的测试

另一项取消销售的测试

并且......等等

所有这些测试都将从与简单测试相同的前四个步骤开始,这将打破DRY原则。 那么我怎么能这样做,以便第二次测试的第一步只运行第一次测试?例如:

Given I have run the create sales order test  // right here it just runs the first test
And I add a sales order line
Then the order total is updated

如果每个测试都以相同的前四行开始,后来我意识到我需要更改简单的创建销售测试,那么我还需要去寻找并修复重复这四行的其他地方。

编辑:请注意,这也应该能够跨功能。例如,上面的简单测试在销售功能中定义。但我也有一个学分功能,这需要每次创建一个销售,以便能够归功于它:

Given I want to credit a sale
And I run the create sales order test
And I complete the the sale
And I click the credit button
Then the sale is credited

4 个答案:

答案 0 :(得分:16)

如前所述,您可以使用背景(在大多数情况下这可能是最佳选择),但您也可以创建调用其他步骤的步骤。

[Binding]
public class MySteps: Steps //Inheriting this base class is vital or the methods used below won't be available
{
    [Given("I have created an order")]
    public void CreateOrder()
    {
         Given("I want to create a sales order");
         Given("I open the sales order page");
         Given("I click the add new order button");
         Then("a new sales order is created");
    }
}

然后您可以在您的场景中使用

Scenario: I add another sale
    Given I have created an order
    When I add a sales order line
    Then the order total is updated

这样做的好处是,此复合步骤可以在场景中的任何位置使用,而不仅仅是作为起点。如果需要,可以在多个功能中重复使用此步骤

答案 1 :(得分:6)

使用背景:

Background:
    Given I want to create a sales order
    And I open the sales order page
    And I click the add new order button
    Then a new sales order is created

Scenario: I add another sale
    When I add a sales order line
    Then the order total is updated

Scenario: I add cancel a sale
    When I cancel a sale
    Then the order total is updated to 0

etc.

答案 2 :(得分:4)

您无需运行实际步骤来创建销售订单。只需实现一个步骤定义,为您做一个单行。

首先,虚构的SalesOrder类:

public class SalesOrder
{
    public double Amount { get; set; }
    public string Description { get; set; }
}

然后是步骤定义

using TechTalk.SpecFlow;
using TechTalk.SpecFlow.Assist;

[Binding]
public class SalesOrderSteps
{
    [Given("I have already created a Sales Order")]
    public void GivenIHaveAlreadyCreatedASalesOrder()
    {
        var order = new SalesOrder()
        {
            // .. set default properties
        };

        // Save to scenario context so subsequent steps can access it
        ScenarioContext.Current.Set<SalesOrder>(order);

        using (var db = new DatabaseContext())
        {
            db.SalesOrders.Add(order);
            db.SaveChanges();
        }
    }

    [Given("I have already created a Sales Order with the following attributes:")]
    public void GivenIHaveAlreadyCreatedASalesOrderWithTheFollowingAttributes(Table table)
    {
        var order = table.CreateInstance<SalesOrder>();

        // Save to scenario context so subsequent steps can access it
        ScenarioContext.Current.Set<SalesOrder>(order);

        using (var db = new DatabaseContext())
        {
            db.SalesOrders.Add(order);
            db.SaveChanges();
        }
    }
}

现在,您可以将销售订单创建为单行,并可选择包含一些自定义属性:

Scenario: Something
    Given I have already created a Sales Order

Scenario: Something else
    Given I have already created a Sales Order with the following attributes:
        | Field       | Value             |
        | Amount      | 25.99             |
        | Description | Just a test order |

如果您需要访问其他步骤定义中的SalesOrder对象而不在数据库中查询它,请使用ScenarioContext.Current.Get<SalesOrder>()从方案上下文中检索该对象。

答案 3 :(得分:-1)

如果我正确理解了这个问题,您希望在不同的功能文件中调用其他方案。

  1. 您可以通过创建调用步骤的步骤来处理此问题 场景(基本上嵌套的步骤,如接受的答案 上文)。
  2. 将创建的步骤添加到背景
    1. 创建一个可以调用场景中的步骤的函数。
    2. 将标记@create_sale_order添加到需要销售订单作为前提条件的方案中。
    3. 为标记@create_sale_order实现之前的场景挂钩,并调用在步骤1中创建的函数。