2011-03-03 8 views
5

Deseo ser capaz de escribir pruebas de la siguiente manera:¿Cómo puedo hacer que specflow se adapte bien a las fechas/horas?

Background: 
    Given a user signs up for a 30 day account 

Scenario: access before expiry 
    When they login in 29 days 
    Then they will be let in 

Scenario: access after expiry 
    When they login in 31 days 
    Then they will be asked to renew 

Scenario: access after acounnt deleted 
    When they login in 2 years time 
    Then they will be asked to register for a new account 

¿cómo lo hago el lado specflow de las pruebas?

Editar: ¿cómo pueden las mismas definiciones de paso hacer frente tanto a "31 días" y "tiempo de 2 años"

Respuesta

1

Creo que puede estar buscando StepArgumentTransformation.

Para hacer frente a 'en 31 días', los documentos tienen para usted:

[Binding] 
public class Transforms 
{ 
    [StepArgumentTransformation(@"in (\d+) days?")] 
    public DateTime InXDaysTransform(int days) 
    { 
     return DateTime.Today.AddDays(days); 
    } 
} 

Y para '' en 2 años, se puede ver el patrón ...

[StepArgumentTransformation(@"in (\d+) years?")] 
    public DateTime InXYearsTransform(int years) 
    { 
     return DateTime.Today.AddYears(years); 
    } 
+0

Creo que StepArgumentTransformation se agregó a Specflow algún tiempo después de que hice esta pregunta .... –

+0

Ah, cierto. Todavía surgió en mi búsqueda de una [pregunta relacionada] (http://stackoverflow.com/questions/40553847/specflow-step-argument-transformation-on-table-cell-contents-with-createinstance), por lo que para otros ' motivo... –

3

La construcción de este archivo .feature creará un código detrás de las pruebas. Luego necesita conectar cada paso a un método. La forma más fácil de hacerlo es

1: depurar las pruebas, la prueba no será concluyente. En cuanto a los resultados de ejecución de prueba, el flujo de especificaciones lo ayuda agregando una plantilla para esta prueba. el mensaje de error se verá algo como esto

Assert.Inconclusive failed. No se encontró una definición de paso coincidente para uno o más pasos.

[Binding] 
public class StepDefinition1 
{ 
    [Given(@"a user signs up for a 30 day account")] 
    public void GivenAUserSignsUpForA30DayAccount() 
    { 
    } 

    [When(@"they login in 29 days")] 
    public void WhenTheyLoginIn29Days() 
    { 
     ScenarioContext.Current.Pending(); 
    } 

    [Then(@"they will be let in")] 
    public void ThenTheyWillBeLetIn() 
    { 
     ScenarioContext.Current.Pending(); 
    } 
} 

2: Copiar en un archivo nuevo paso specflow definición, que es clase de prueba, básicamente, sólo la unidad poblada de atributos specflow. Ahora hay algunos trucos que puede hacer para ayudarlo. en el método GivenAUserSignsUpForA30DayAccount crearía un usuario que se usará en la prueba que tiene una cuenta de prueba de 30 días. Un miembro privado trabajaría bien aquí para que pueda acceder a ellos entre métodos, pero esto solo funciona si todos los métodos están en la misma clase. Si intenta volver a utilizar métodos entre varias características/clases, tendrá que considerar guardar su objeto en ScenarioContext

3: Cuando se ejecuta la prueba de espectroscopio, busca un método que tenga un atributo coincidente con la misma cadena. Un truco aquí es que puedes pasar parámetros al método usando comodines en el atributo de método. Hay 2 tarjetas de archivos diferentes

(. *) Significa que está pasando una cadena a ese método (\ d +) significa que está pasando un int a ese método.

Como su método When es común, puede reutilizarlo con parámetros como este.

[When(@"they login in (\d+) days")] 
    public void WhenTheyLoginInDays(int daysRemaining) 
    { 
     Account.DaysRemaining = daysRemaining; 
    } 

4: finalmente agregue sus Asserts en el método Then para que el resultado final se vea más o menos así. (Nota que en lo personal me gustaría reestructurar la redacción de la función un poco y pasarlo espera que los resultados de esa manera la lógica de prueba no es tan desagradable como mi ejemplo, mira escenario describe para los datos de las pruebas conducidas)

[Binding] 
public class StepDefinition1 
{ 
    UserAccount user; 

    [Given(@"a user signs up for a 30 day account")] 
    public void GivenAUserSignsUpForA30DayAccount() 
    { 
     user = AccountController.CreateNewUser("bob", "password", AccountType.Trial); 
    } 

    [When(@"they login in (\d+) days")] 
    public void WhenTheyLoginInDays(int daysRemaining) 
    { 
     Account.DaysRemaining = daysRemaining; 
    } 

    [Then(@"they will (.*)")] 
    public void ThenTheyWillBeLetIn(string expected) 
    { 
     //check to see which test we are doing and then assert to see the expected result. 
     if(string.Compare(expected, "be let in", true) 
      Assert.AreEqual(LoginResult.Passed, LoginService.Login); 
     if(string.Compare(expected, "be asked to renew", true) 
      Assert.AreEqual(LoginResult.Passed, LoginService.Login); 

    } 
} 
+0

gracias para la mejor respuesta, sin embargo, me perdí parte de mi pregunta que ahora he corregido, ¡lo siento por mover las publicaciones! Por ejemplo, ¿cómo pueden las mismas definiciones de pasos lidiar con "31 días" y "2 años de tiempo"? –

3

I se enfrentó a un problema similar con la forma de lidiar con relativas a las fechas y horas de en SpecFlow, y se le acercó dando soporte a fechas difusas dentro de las especificaciones. He utilizado el código de esta respuesta: Fuzzy Date Time Picker Control in C# .NET?, lo que permitirá expresar lo que quiere de la siguiente manera:

 
Background: 
    Given a user signs up for a 30 day account 

Scenario: access before expiry 
    When they login in the next 29 days 
    Then they will be let in 

Scenario: access after expiry 
    When they login in the next 31 days 
    Then they will be asked to renew 

Scenario: access after account deleted 
    When they login in the next 2 years 
    Then they will be asked to register for a new account 

Con una definición de paso, tales como:

 
[When(@"they login in the (.*)")] 
public void WhenTheyLoginIn(string loginDateTimeString) 
{ 
    DateTime loginDateTime = FuzzyDateTime.Parse(loginDateTimeString); 

    // TODO: Use loginDateTime 
} 

Si no les gusta la sintaxis para las fechas difusas, puede modificar las expresiones regulares en el código FuzzyDateTime para adaptarlas.

1
> how can the same step definitions cope with both "31 days" and "2 years time" 

Si las reglas no necesitan un tratamiento especial para la jornada de trabajo, navidad, fin de semana, ... se puede modificar @ s Nitro52-respuesta a:

[When(@"they login in (\d+) days")] 
public void WhenTheyLoginInDays(int daysRemaining) 
{ 
    Account.RegristrationDate = DateTime.ToDay().SubtractDays(daysRemaining); 
    Account.VerificationDate = DateTime.ToDay();  
} 

Tal vez también se puede pensar en la reformulación de los escenarios como esto

Scenario: access before expiry 
    When they login on '2010-01-01' 
    And TodayIs '2010-01-29' 
    Then they will be let in 
-2

Trate de usar Moles y derivadas la DateTime.Now para devolver el mismo cada día. Una de las mejores características de Moles es la capacidad de convertir dang cerca de cualquier cosa en un delegado de tiempo de ejecución que puedes aislar. El único inconveniente es que puede funcionar más lento según la implementación que elija (troquelado frente a moled). Estoy empezando a bucear, así que tome mi sugerencia con un grano de sal.

1

Sé que luché con esto durante mucho tiempo. Me tomó un tiempo cambiar mi código existente, pero matar todas las referencias a DateTime.Now y reemplazarlas con una interfaz que podría simular ha hecho que todo sea un millón de veces más fácil de probar (y cambiar más adelante). Creé un IDateTimeService que tiene un método "GetCurrent()". Ahora todos mis pasos dados pueden decir:

Given the current date is '2/4/12' 
And the user's account was created on '1/24/12' 

Entonces puedo hacer la comprobación de rango mucho más fácil.

La etapa para la fecha actual se parece a:

[Given(@"Given the current date is '(.*)'")] 
public void GivenTheCurrentDateIs(string date) 
{ 
    var dateServiceMock = new Mock<IDateTimeService>(); 
    dateServiceMock.Setup(ds => ds.GetCurrent()).Returns(DateTime.Parse(date)); 
    ScenarioContext.Current.Add("dateService", dateServiceMock); 
} 
Cuestiones relacionadas