【问题标题】:How to properly indicate which StepArgumentTrasformation to use with step?如何正确指示与步骤一起使用的 StepArgumentTransformation?
【发布时间】:2014-06-06 18:09:33
【问题描述】:

我正在尝试在两个不同的步骤中将 SpecFlow 步骤参数转换为相同的返回类型。

这是简化的功能文件:

Feature: TransforMe

@UseTableToIntsTransform
Scenario: First
Given I have some condition
When I do something
Then the results should be
| Index |
| 1     |
| 2     |
| 3     |

@UseStringToIntsTransform
Scenario Outline: Second
Given I have some condition
When I do something
Then the results should contain <expectedResults>

Examples: 
| expectedResults |
| 0               |
| 0,3,5,7,10      |

我要做的是从 Then 步骤中的场景转换 Table 和 string 以将 IEnumerable 作为 step 参数返回。我正在尝试使用范围,属性正则表达式限制,......没有成功。以下是步骤定义:

[Binding]
public class TransforMeSteps
{
    [Given(@"I have some condition")]
    public void GivenIHaveSomeCondition()
    { }

    [When(@"I do something")]
    public void WhenIDoSomething()
    { }

    [Then(@"the results should be")]
    [Scope(Scenario = "First", Tag = "UseTableToIntsTransform")]
    public void ThenTheResultsShouldBe(IEnumerable<int> results)
    {
        results.ToList().ForEach(x => Debug.WriteLine(x));
    }

    [Then(@"the results should contain (.*)")]
    [Scope(Scenario = "Second", Tag = "UseStringToIntsTransform")]
    public void ThenTheResultsShouldContain(IEnumerable<int> results)
    {
        results.ToList().ForEach(x => Debug.WriteLine(x));
    }
}

[Binding]
[Scope(Scenario = "First", Tag = "UseTableToIntsTransform")]
public class TableToIntsTransform
{
    [StepArgumentTransformation(@"the results should be")]
    public IEnumerable<int> TableToInts(Table intsTable)
    {
        return new List<int> { 1, 2, 3 };
    }
}

[Binding]
public class StringToIntsTransform
{
    [StepArgumentTransformation(@"the results should contain (.*)")]
    [Scope(Scenario = "Second", Tag = "UseStringToIntsTransform")]
    public IEnumerable<int> StringToInts(string integersString)
    {
        return new List<int> { 4, 5, 6 };
    }
}

对于“第一个”场景,我得到了绿色测试,但有警告:多步转换与输入匹配(| 索引 | | 1 | | 2 | | 3 | ,目标类型:[System.Collections.Generic.IEnumerable`1[System.Int32]])。我们使用第一个。

对于“第二个”场景,抛出 InvalidCastException:Invalid cast from 'System.String' to 'System.Collections.Generic.IEnumerable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral , PublicKeyToken=b77a5c561934e089]]'。

每个转换都通过相应的步骤定义自行工作。例如,如果我将转换类的顺序更改为首先具有 StringToIntsTransform,那么“第二”场景的测试是绿色的。

那么我如何正确地指示或限制正确转换的范围?

我希望有这样的东西作为我的最终解决方案:

    [Then(@"the results should contain (.*)")]
    [Then(@"the results should be")]
    public void ThenTheResultsShouldContain(IEnumerable<int> results)
    {
        results.ToList().ForEach(x => Debug.WriteLine(x));
    }

所以只有一步定义。

【问题讨论】:

    标签: specflow


    【解决方案1】:

    这可能并不理想,但我要做的是创建一个类来表示我要返回的对象并在此处使用它。这个类可能只是简单地包装一个 int,但是作为一个不同的类将允许 specflow 区分要使用的步骤转换。所以大致如下:

    [Binding]
    public class TransforMeSteps
    {
        [Given(@"I have some condition")]
        public void GivenIHaveSomeCondition()
        { }
    
        [When(@"I do something")]
        public void WhenIDoSomething()
        { }
    
        [Then(@"the results should be")]
        [Scope(Scenario = "First", Tag = "UseTableToIntsTransform")]
        public void ThenTheResultsShouldBe(IEnumerable<Index> results)
        {
            results.ToList().ForEach(x => Debug.WriteLine(x));
        }
    
        [Then(@"the results should contain (.*)")]
        [Scope(Scenario = "Second", Tag = "UseStringToIntsTransform")]
        public void ThenTheResultsShouldContain(IEnumerable<ExpectedResult> results)
        {
            results.ToList().ForEach(x => Debug.WriteLine(x));
        }
    }
    
    [Binding]
    [Scope(Scenario = "First", Tag = "UseTableToIntsTransform")]
    public class TableToIntsTransform
    {
        [StepArgumentTransformation(@"the results should be")]
        public IEnumerable<Index> TableToInts(Table intsTable)
        {
            return new List<Index> { 1, 2, 3 };
        }
    }
    
    [Binding]
    public class StringToIntsTransform
    {
        [StepArgumentTransformation(@"the results should contain (.*)")]
        [Scope(Scenario = "Second", Tag = "UseStringToIntsTransform")]
        public IEnumerable<ExpectedResult> StringToInts(string integersString)
        {
            return new List<ExpectedResult> { 4, 5, 6 };
        }
    }
    
    public class Index
    {
         private int value;
         public Index(int value)
         { this.value=value;}
    
         public static implicit operator int(Index index)
         {
             return index.value;
         }
    
         public static implicit operator Index(int value)
         {
             return new Index(value);
         }
    }
    

    您也许可以将 IndexExpectedResult 类隐式转换为 int 以使其更方便使用。

    【讨论】:

    • 嗨,山姆,感谢您的帮助。我想当我想使用多个 IEnumerable 转换时,这样的事情会导致类似的问题。 SpecFlow 可能会再次使用第一个,然后我们回到第一个。
    • 没问题。我可能会使用一个不同的类(可能与 Index 几乎相同)来代表被转换的东西。这使事情变得整洁、易于理解,因为一切都是根据业务对象而不仅仅是“计算机概念”
    • 这种方式可能很有用,但是我不会更接近我想要得到的东西:两个或多个绑定到同一个步骤,不要在代码中重复自己(DRY) .
    • @lucky3 这是真的。你付你的钱你选择。这都是一个权衡......祝你好运!
    猜你喜欢
    • 1970-01-01
    • 2015-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多