В 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

И я хочу провести еще один тест, который проверяет добавление строки продаж

И еще один тест, который тестирует завершение продажи

И еще один тест, который отменяет продажу

И так далее

Все эти тесты начинаются с тех же первых четырех шагов, что и простой тест, который нарушает принцип СУХОЙ. Так как я могу сделать так, чтобы первый шаг 2-го теста просто запустил первый тест? например что-то вроде:

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 ответа

Решение

Как уже отмечалось, вы можете использовать фон для этого (и это, вероятно, лучший вариант в большинстве ситуаций), но вы также можете создать шаг, который вызывает другие шаги.

[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

Преимущество этого заключается в том, что этот составной шаг можно использовать в любом месте сценария, а не только в качестве отправной точки. Этот шаг может быть повторно использован для нескольких функций, если вам нужно

Используйте фон:

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.

Вам не нужно выполнять реальные шаги для создания заказа на продажу. Просто реализуйте определение шага, которое делает это для вас как для одной строки.

Во-первых, вымышленный 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>() извлечь этот объект из контекста сценария.

Если я правильно понимаю вопрос, вы хотите вызвать другие сценарии для разных файлов функций.

  1. Вы можете справиться с этим, создав шаг, который будет вызывать шаги в сценарии (в основном вложенные шаги, такие как принятый ответ выше).
  2. Добавьте созданный шаг в фон

или же

  1. Создайте функцию, которая будет вызывать шаги в сценарии.
  2. Добавьте тег @create_sale_order в сценарии, для которых в качестве предварительного условия требуется заказ на продажу.
  3. Реализуйте хук перед сценарием для тега @create_sale_order и вызовите функцию, созданную на шаге 1.
Другие вопросы по тегам