0

I have a couple of Specflow's features file which contain multiple scenarios and I want to execute them against multiple environments (DEV, TEST, and SIT).

So, my question here is - what is the best way to pass environment specific data from feature file to step definition. As you can see in the example below employee records are different in each environment.

Scenario Outline: Employee Search
Given Application is logged
And Search for employee record with <EmployeeName>, <EmployeeID>, <Company>, <Designation> and <Environment>
 Examples: 
        | EmployeeName| EmployeeID| Company  | Designation | Environment |
        | John Smith 1| 123       | ABC      | Analyst     | DEV         |
        | John Smith 2| 456       | DFG      | Manager     | TEST        |
        | John Smith 3| 789       | XYZ      | Sr Analyst  | SIT         |

[When(@"Search for employee record with (.*), (.*), (.*), (.*) and (.*)")]
    public void WhenSearchEmployee (string EmployeeName, string EmployeeID, string Company, string Designation, string Environment)
    {
        if (Environment== "DEV")
        {
            EmployeeRecord.SearchEmployee(EmployeeName, EmployeeID, Company, Designation);
        }
        else if (Environment== "TEST")
        {
            EmployeeRecord.SearchEmployee(EmployeeName, EmployeeID, Company, Designation);
        }
        else if (Environment== "SIT")
        {
            EmployeeRecord.SearchEmployee(EmployeeName, EmployeeID, Company, Designation);
        }
    }

Edits

  • I'm identifying the environment with app.config file

Basically, I want to execute the same test case in multiple environments (one at a time) with different data. Also if I have two rows in examples table, how to execute only once based on the environment.

Is this the right approach? Thanks.

SK.
  • 4,174
  • 4
  • 30
  • 48
  • That will work. To make the steps repeatable in any environment though, can you create the test case in an end to end format and create the employee record first and then search in the same test case? This way environment is irrelevant. – Dazed Aug 01 '19 at 01:55
  • Also - if you go with this format, how are you setting the env that you are running? Setting it in the appconfig and using configuration manager or setting locally for each run with setx? – Dazed Aug 01 '19 at 02:13
  • For sure this is not an approach that I would recommend, as the logic with in the method does not differ between the environments - why we need that conditional check in the method. Instead you can make this as `scenario` and pass the details as `datatable` then get the environment from the appconfig and sort the required data from the datatable with matching environment. Let me know if you have any questions on that approach. – supputuri Aug 01 '19 at 03:43
  • @Dazed - 1. Above code is just an example but the actual test cases I have are much more complex than this. I can't create few types of records from UI but I have to perform a search on those. 2. I'm using appconfig and configuration manager. – SK. Aug 01 '19 at 04:02
  • @supputuri - The logic in the method to pass different data based on the environment. If you see the examples table above, I have different data for DEV, TEST, and SIT. – SK. Aug 01 '19 at 04:05
  • @supputuri - can you share some example/link with `datatable`? Basically, I want to execute the same test case in multiple environments with different data – SK. Aug 01 '19 at 04:16

2 Answers2

1

If you can't create on demand each time, here is another way.

Create a data.cs file.

public class EnvData
{
    public EnvData()
    {
        { 
            defaultEmail = "test@gmail.com";
            defaultPassword = "MyPass123";
        }


        if(ConfigurationManager.AppSettings["Env"] == "Test")
        {
            empName = "John Smith";
            EmployeeID = "1234";
            Company = "McDonalds";
            Designation = "McManager";
           
        }
        else if (ConfigurationManager.AppSettings["Env"] == "Dev")
        {
            empName = "Joe Smith";
            EmployeeID = "3456";
            Company = "McDonalds";
            Designation = "FryGuy";
           
        }
    }

      public static string defaultEmail;
      public static string defaultPassword;
      public static string empName;
      public static string EmployeeID;  //can be an int
      public static string Company;
      public static string Designation;

  }
}

Then in your step file we use context injection - https://specflow.org/documentation/context-injection/

    private readonly EnvData _envData;

    public MyClassName(EnvData envData)
    {
        _envData = envData;
    }

The reason you do it this way is that if you need to change the data, you change it in one area and not in each test case.

Scenario: Employee Search
Given Application is logged
And Search for an employee


  [When(@"Search for employee]
  public void WhenSearchEmployee ()
  {

  //would look something like this...

          EmployeeRecord.SearchEmployee(envData.empName, envData.EmployeeID, envData.Company, envData.Designation);
   
       }

So in the above, the step will hit envData and based on the appconfig value for the environment, it will pull whatever employee info you set. This works great if your data is static. I still prefer creating the search criteria first and then searching so you do not have to do all this lol.

Dazed
  • 1,527
  • 1
  • 13
  • 25
  • Looks great but what if I have to run same test case multiple time like we have multiple rows in `examples` table with data then it will run for the first row then the second row then the third row... so on... Creating the search record wouldn't be possible but thanks for the suggestion, lol... – SK. Aug 02 '19 at 00:23
  • Why would you use an example table? Example tables are used when you are passing data to the step. Example tables should also rarely be used if ever. In this scenario, you are passing data from a data.cs file that has the data specified for each environment vs the feature. Your feature would be "Given I search on Name, EmpId, Designation and Company". The step would call envData.Name based on the environment set in the app.config and would use that set data. – Dazed Aug 02 '19 at 00:39
0

Since you are already passing the environment in the step, I would personally pass that value to a database object constructor that switches the connection string from your app.config based on the constructor input.

Example using Entity Framework:

public void WhenSearchEmployee (string EmployeeName, string EmployeeID, string Company, string Designation, string Environment) {    
    using (var context = new SomeContext(Environment)) {        
         // Search Employee code here
    }
}

Then you can pass that value to the DbContext base class which can select your environment by matching the name parameter from your app.config <connectionStrings>. EF will do this automatically, but if you're using ado.net you can still do something similar.

public partial class SomeContext : DbContext {
    public SomeContext(string dbName) : base($"name={dbName}") {
    }
}

In the end, anytime you need to use an environment specific database for your steps, calling this context and passing the environment name will make all your steps generic enough to not care which environment they are executing against.