如何使步骤参数依赖于配置?

时间:2015-06-11 12:28:54

标签: c# specflow gherkin

问题

我正在使用SpecFlow为REST服务创建集成测试套件。

我在多个不同的配置中运行套件。 (我有多个Build配置,每个配置都有自己的app.config转换集。)
在C#代码中,检查配置并基于它执行不同的代码非常简单。我可以简单地做这样的事情。

[Given(@"I set the test parameter to ""(.*)""")]
public void GivenISetTheTestParameter(string parameter)
{
    if(CurrentConfiguration == Config.Test)
        this.testParameter = parameter + "Test";
    else if(CurrentConfiguration == Config.Prod)
        this.testParameter = parameter + "Prod";
}

这种方法的问题在于它在每次执行此步骤时都以相同的方式工作,但我不想在每种情况下以不同方式参数化步骤中与配置相关的部分。
有没有办法在功能文件中执行此操作?我想做这样的事情(伪代码,当然这不起作用):

If (CurrentConfiguration == Config.Test)
Given I set the test parameter to "ParameterTest"
Else If (CurrentConfiguration == Config.Prod)
Given I set the test parameter to "ParameterProd"

然后我可以在每个场景中以不同的方式使用此参数化:

Scenario: Test 1
    If (CurrentConfiguration == Config.Test)
    Given I set the test parameter to "ParameterTest1"
    Else If (CurrentConfiguration == Config.Prod)
    Given I set the test parameter to "ParameterProd1"
    ...

Scenario: Test 2
    If (CurrentConfiguration == Config.Test)
    Given I set the test parameter to "ParameterTest2"
    Else If (CurrentConfiguration == Config.Prod)
    Given I set the test parameter to "ParameterProd2"
    ...

如果条件是在步骤的C#代码中实现的,那么这是不可能的。

真实世界的例子

我想用它来集成测试REST服务。我们假设我使用基本身份验证,我需要在RestClient对象上设置标头。
我有一个帮助步骤,用于将auth标头设置为特定的用户名和密码。

棘手的部分是我有多个构建配置(让我们说Staging和Prod),我需要不同的测试凭据。此外,我在我的功能的不同场景中调用不同的API,这也需要不同的凭据。

因此,使用上面介绍的伪语法,这就是我想要做的事情:

Scenario: Test LoggingService
    If (CurrentConfiguration == Config.Test)
        Given I set the auth header for the user "logging_test_user" and password "p4ssword"
    Else If (CurrentConfiguration == Config.Prod)
        Given I set the auth header for the user "logging_prod_user" and password "p4ssword"
    ...
    When I call the LoggingService
    ...

Scenario: Test PaymentService
    If (CurrentConfiguration == Config.Test)
        Given I set the auth header for the user "payment_test_user" and password "p4ssword"
    Else If (CurrentConfiguration == Config.Prod)
        Given I set the auth header for the user "payment_prod_user" and password "p4ssword"
    ...
    When I call the PaymentService
    ...

如果我只能将条件放入&#34的C#实现中;鉴于我设置了auth标头......"一步,那么我就无法为不同的场景指定不同的用户名。

5 个答案:

答案 0 :(得分:2)

您根本不需要功能文件中的可配置数据。而是创建一个通用步骤,其定义读取配置文件:

Scenario: Test LoggingService
    Given I set the auth header

在C#中:

[Given(@"I set the auth header")]
public void GivenISetTheAuthHeader()
{
    string username = System.Configuration.ConfigurationManager.AppSettings["RestServiceUserName"];
    string password = System.Configuration.ConfigurationManager.AppSettings["RestServicePassword"];
}

在App.config中:

<appSettings>
  <add key="RestServiceUserName" value="..."/>
  <add key="RestServicePassword" value="..."/>

如果不同的用户名在系统中具有不同的权限,请考虑改为使用场景大纲:

Scenario Outline: Testing the LoggingService
    Given I set the auth header for user "<Username>" and password "<Password>"

Examples:
    | Username | Password |
    | user1    | pass1    |
    | user2    | pass2    |

它们成为步骤定义的正常参数:

[Given("I set the auth header for user """(.*)""" and password """(.*)"""")]
public void GivenISetTheAuthHeaderForUserAndPassword(string username, string password)
{
    // set the user and password on the auth header
}

答案 1 :(得分:1)

我们针对不同的环境做了类似的事情,但是我们有一个app.config用于测试,其中有几个&#39; alternate&#39; dev,qa和uat的配置,我们从其中一个部分读取命名参数的值。

我们有类似的东西

<testingEnvironments>
  <testingEnvironment name="Dev" messageUrl="https://somedevurl/" isCurrent="true">
     <ConfigParam1>SomeValue</ConfigParam1>
  </testingEnvironment>
  <testingEnvironment name="QA" messageUrl="https://somedqaurl/" isCurrent="false">
     <ConfigParam1>SomeValueInQA</ConfigParam1>
  </testingEnvironment>
  <testingEnvironment name="UAT" messageUrl="https://someuaturl/" isCurrent="false">
     <ConfigParam1>SomeValueUAT</ConfigParam1>
  </testingEnvironment>
</testingEnvironments>

我们根据isCurrent属性的值选择配置,但您可以根据环境变量在名称上选择它。

然后您的测试不知道所使用的确切值,然后只需参考ConfigParam1

基于您的真实世界示例,我不喜欢测试中的实现细节(如果您使用其他一些身份验证机制会怎样),并会重构我的规范:

Scenario: Test LoggingService
    Given I am the logging service default user for the current environment     
    When I call the LoggingService
    ...

Scenario: Test payment Service
    Given I am the payment service default user for the current environment     
    When I call the PaymentService
    ...

并添加如下所示的配置:

  <testingEnvironment name="DEV" messageUrl="https://somedevurl/" isCurrent="false">
     <userCredentials>
          <LoggingService>
             <defaultUser name="logging_test_user" password="p4ssword" />                 
          </LoggingService>
          <PaymentService>
             <defaultUser name="payment_test_user" password="p4ssword" />                 
          </PaymentService>
     </userCredentials>         
  </testingEnvironment>
  <testingEnvironment name="UAT" messageUrl="https://someuaturl/" isCurrent="false">
     <userCredentials>
          <LoggingService>
             <defaultUser name="logging_prod_user" password="p4ssword" />                 
          </LoggingService>
          <PaymentService>
             <defaultUser name="payment_prod_user" password="p4ssword" />                 
          </PaymentService>
     </userCredentials>         
  </testingEnvironment>

然后,您的各个步骤可以调用常用步骤来设置实际标题值

答案 2 :(得分:1)

你可以通过场景大纲和标记的示例实现你想要的,但是你必须在某些环境中只运行一些测试:

Scenario Outline: Testing the LoggingService
    Given I set the auth header for user "<Username>" and password "<Password>"

@Production
Examples:
    | Username          | Password |
    | logging_prod_user | p4ssword |
@Test
Examples:
    | Username          | Password  |
    | logging_test_user | p4assword |

然后配置您的测试运行器以仅运行某些类别的测试(TestProduction

如果您使用nunit(或XUnit或任何其他默认使用行测试运行场景大纲的测试运行器)作为测试运行器,请注意this issue

答案 3 :(得分:0)

您的测试应始终相同 - 其中包含“if”的测试至少需要进行两次测试。解决这个问题的正确方法是隔离被测系统,使其获取表示配置值的参数(或以其他方式提供值),然后为所有适用的场景编写测试。

答案 4 :(得分:0)

我会写这个功能:

Scenario: Test LoggingService
    Given I set the auth header with valid user and password
    When I call the LoggingService
    # ...

设置App.config文件:

<appSettings>
    <add key="EnvironmentUserName" value="..."/>
    <add key="EnvironmentPassword" value="..."/>
    <!-- ... -->
</appSettings>

并执行以下步骤:

public void GivenISetTheAuthHeader()
{
    string username = System.Configuration.ConfigurationManager.AppSettings["EnvironmentUserName"];
    string password = System.Configuration.ConfigurationManager.AppSettings["EnvironmentPassword"];
    // ...
 }