Можно ли в Specflow запустить один тест как шаг другого?

TL;DR; Как создать тест спецификации, который вызывает другой тест в качестве первого шага?

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

person JK.    schedule 17.03.2015    source источник
comment
Создание шага Given I have run the create sales order test, который выполняет три предыдущих метода шагов Given, не работает? Или вы хотите по-другому? Я сомневаюсь, что вы захотите повторить часть Assert в следующих тестах.   -  person Pierre-Luc Pineault    schedule 18.03.2015
comment
Я не возражаю, что ему придется повторять утверждения, которые будут существовать в первом тесте. Я хочу иметь возможность запускать его без необходимости писать одни и те же 4 шага во множестве разных тестов.   -  person JK.    schedule 18.03.2015
comment
да, но почему бы вам не создать новую Given наподобие вашей части «что-то вроде», которая вызывает три предыдущих Given вручную? Также подходит для сценария в вашем редактировании, так как вы можете повторно использовать свой I have run the create sales order test шаг, где хотите. Вы были там на 99% в своем вопросе.   -  person Pierre-Luc Pineault    schedule 18.03.2015
comment
@Pierre-LucPineault Я думаю, что ОП не знает об этом как о возможности, и это то, о чем он просит   -  person Sam Holder    schedule 18.03.2015


Ответы (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

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

person Sam Holder    schedule 17.03.2015
comment
Спасибо, это довольно близко на самом деле. Однако я все еще хочу, чтобы в первом тесте шаги были записаны в файле функций, поэтому некоторое дублирование все же будет (но только 2 раза вместо n раз). - person JK.; 18.03.2015
comment
Это нормально. Вы можете использовать шаги, если хотите, или вы можете сгруппировать их вместе с «составным» шагом, который вам нужен. Это дает лучшее из обеих работ - person Sam Holder; 18.03.2015
comment
Несколько вещей, которых следует опасаться: 1. вам нужно использовать правильный Given(...) When(...) Then(...) или And(...) в соответствии с вашим определением шага и 2. если вы используете И после шага, то он унаследует то, что вы последний раз использовали в коде, а не то, что вы последний раз использовали в файле функций. - person Steve; 18.07.2016
comment
Эта ошибка должна быть исправлена ​​в следующем выпуске @steve - person Sam Holder; 18.07.2016
comment
@SamHolder Я думал, что это особенность :) - person Steve; 18.07.2016
comment
Я вижу только пару проблем с этим: 1) если вы измените базовый сценарий, вы должны изменить определение шага CreateOrder, чтобы оно соответствовало тому, что подвержено ошибкам пользователя 2) сложно параметризовать данные, используемые базовым сценарием. Есть ли способ автоматически сгенерировать определение шага для I have created an order, чтобы оно соответствовало определению сценария? - person MikeW; 07.12.2016
comment
Это не лучший вариант. Во-первых, он динамически связывает вызов метода во время выполнения, поэтому, если вы обновите определение шага и забудете об этом месте, то он даже не выйдет из строя, он просто попытается вызвать метод и молча пропустит его, если не сможет найти нужный. метод сопоставления. Это очень раздражает, когда приходится отлаживать. - person metabuddy; 01.06.2018

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

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.
person RagtimeWilly    schedule 17.03.2015
comment
Это выглядит хорошо, но будет работать только в рамках одной функции, верно? Есть ли способ повторно использовать тест для нескольких функций? Я обновлю вопрос. - person JK.; 18.03.2015
comment
Вы можете использовать [BeforeTestRun] или [BeforeScenario], но тогда это будет применяться к каждому сценарию. Я не уверен, что ты этого хочешь? - person RagtimeWilly; 18.03.2015
comment
Нет, это будет только для конкретных связанных тестов. Тесты, которые начинаются одинаково, но затем продолжают тестировать что-то еще. - person JK.; 18.03.2015

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

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

person Greg Burghardt    schedule 19.03.2015

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

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

or

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