2011-03-03 66 views
5

我希望能够编写测试是这样的:如何使specflow能够很好地处理日期/时间?

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 

我该怎么做测试的specflow的一面呢?

编辑:如何能在同一步骤定义应付两个“三一的日子”和“2年多的时间”

回答

1

我想你可能会寻找StepArgumentTransformation

要以“在31天的处理,该文档有它给你:

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

而对于“2年”,你可以看到的图案......

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

我认为StepArgumentTransformation是在我问这个问题后的一段时间里被添加到Specflow中的。 – 2016-11-11 18:14:55

+0

啊,真的。它仍然出现在我的搜索[相关问题](http://stackoverflow.com/questions/40553847/specflow-step-argument-transformation-on-table-cell-contents-with-createinstance),所以对于其他人' 清酒... – 2016-11-11 18:24:26

3

建设这个.feature文件的背后会创建一个代码测试。然后您需要将每个步骤连接到一个方法。最简单的方法是,

1:调试测试,测试将失败,因为不确定。查看测试运行结果specflow帮助您通过为此测试添加模板。错误信息看起来像这样

Assert.Inconclusive失败。找不到与一个或多个步骤匹配的步骤定义。

[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:这个复制到一个新的specflow步骤的定义文件,它是填充有specflow属性基本上只是单元测试类。现在有一些技巧可以帮助你。在GivenAUserSignsUpForA30DayAccount方法中,我将创建一个将在具有30天试用帐户的测试中使用的用户。私人成员在这里可以很好地工作,所以你可以在方法之间访问它们,但是只有当所有的方法都在同一个类中时,这才有效。如果您尝试在多个要素/类之间重用方法,则需要考虑将对象保存到ScenarioContext中。3:当specflow测试运行时,它会查找具有匹配属性且具有相同字符串的方法。这里的一个诀窍是你可以使用方法属性中的通配符将参数传递给方法。有两个不同的文件卡

(。*)表示您正在向该方法传递字符串 (\ d +)表示您正在向该方法传递一个int。

因为您的When方法很常见,您可以像这样重用它。

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

4:最后加上你的断言到随后方法,这样最终的结果看起来是这样的。 (请注意,我个人重组功能一点的措辞,并通过它预期的结果这样的测试逻辑并不像我举的例子是讨厌的,看情形概括为数据驱动测试)

[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

感谢为了答复,但是我错过了我现在已经联系的部分问题 - 抱歉移动帖子!例如,相同的步骤定义如何处理“31天”和“2年时间”? – 2011-03-04 17:18:44

3

我面临类似的问题,如何应对相对日期和时间在SpecFlow,并通过支持模糊日期在规范范围内。我使用的代码从这样的回答:Fuzzy Date Time Picker Control in C# .NET?,这将让你表达你想要的东西如下:

 
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 

通过步骤定义,如:

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

    // TODO: Use loginDateTime 
} 

如果你不喜欢的语法对于模糊日期,您可以修改FuzzyDateTime代码中的正则表达式以适应。

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

如果你的规则需要workingday,圣诞节,周末没有特别的处理......你可以修改@ Nitro52-S回答:

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

也许你也可以考虑重新拟订的方案像这样

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

尝试使用Moles并存根DateTime.Now每次返回相同的日期。鼹鼠最好的功能之一是能够将任何东西变成可以隔离的运行时委托。唯一的缺点是它可能会运行速度较慢,这取决于您选择的实施方式(存根与存根)。我刚刚开始深入研究,所以我的建议与一粒盐。

1

我知道我很久以来一直在努力。我花了一段时间来改变我现有的代码,但是将所有对DateTime.Now的引用都取消,并用一个我可以模拟的接口来替换它们,这使得所有的事情都变得更容易测试(以后再进行更改)。我创建了一个具有“GetCurrent()”方法的IDateTimeService。现在,所有我考虑的步骤可以说:

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

然后,我可以做的范围检查方便很多。

当前日期的步骤是这样的:

[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); 
} 
相关问题