c# unit-testing automated-tests dry specflow

c# - En Specflow, ¿puedo ejecutar una prueba como paso de otra?



unit-testing automated-tests (4)

TL; DR; ¿Cómo puedo crear una prueba de flujo de datos que llame a otra prueba como primer paso?

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

Lo siento, un poco de humor specflow allí.

Por ejemplo, tengo una prueba que ya crea una venta:

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

Y quiero tener otra prueba que pruebe agregar una línea de ventas

Y otra prueba que prueba completar la venta

Y otra prueba que cancela la venta

Y así

Todas esas pruebas comenzarían con los mismos primeros cuatro pasos que la prueba simple, que rompe el principio DRY. Entonces, ¿cómo puedo hacerlo para que el primer paso de la segunda prueba solo ejecute la primera prueba? por ejemplo, algo como:

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

Si cada prueba comienza con las mismas primeras cuatro líneas, y más tarde me doy cuenta de que tengo que cambiar la prueba simple de crear una oferta, entonces también tendré que ir a buscar y arreglar todo el resto que repita esas cuatro líneas.

EDITAR: tenga en cuenta que esto también debería poder funcionar a través de las características. Por ejemplo, la prueba simple anterior se define en la función de ventas. Pero también tendría una función de crédito, y eso requeriría crear una venta cada vez para poder acreditarla:

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


Como ya se señaló, puede usar un fondo para esto (y esa es probablemente la mejor opción en la mayoría de las situaciones), pero también puede crear un paso que llame a los otros pasos.

[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"); } }

que puedes usar en tu escenario:

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

Esto tiene la ventaja de que este paso compuesto puede usarse en cualquier parte del escenario y no solo como punto de partida. Este paso puede ser reutilizado en múltiples funciones si necesita


Usa un fondo:

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.


No necesita ejecutar pasos reales para crear un pedido de cliente. Simplemente implemente una definición de paso que lo haga por usted como una línea.

Primero, la clase ficticia SalesOrder :

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

Luego, las definiciones de paso

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(); } } }

Ahora puede crear pedidos de venta como un solo trazo y opcionalmente incluir algunos atributos personalizados:

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 |

Si necesita acceder a ese objeto SalesOrder en otras definiciones de pasos sin consultarlo en la base de datos, use ScenarioContext.Current.Get<SalesOrder>() para recuperar ese objeto del contexto del escenario.


Si entiendo la pregunta correctamente, quiere llamar a otros escenarios en diferentes archivos de características.

  1. Puede manejar esto creando un paso que llamaría los pasos en el escenario (básicamente pasos anidados como la respuesta aceptada arriba).
  2. Agregue el paso creado al fondo

o

  1. Crea una función que llamaría los pasos en el escenario.
  2. Agregue una etiqueta @create_sale_order a los escenarios que necesitan una orden de venta como condición previa.
  3. Implemente un enlace de escenario anterior para la etiqueta @create_sale_order y llame a la función creada en el paso 1.