2

I have below feature with steps and class under test. When I change the Name field visibility to public I can retrieve the value after Table.CreateInstance<>() but when make it private it's failing.

Scenario: Get employee details.

Given below employee create a user.
| Name | age |
| John | 28  |

Code

[Binding]
public class TableSteps
{
    [Given(@"below employee create a user\.")]
    public void GivenBelowEmployeeCreateAUser_(Table table)
    {
        Employee employee = table.CreateInstance<Employee>();
        Console.Write("Name:" + employee.Name); //Works as it is public.
        Console.Write("Name:"+ employee.EmpName); //No value returned here. Just null.
    }
}

public class Employee
{
    private string Name { get; set; } //not working.
    //public string Name { get; set; } //works.
    public int age { get; set; }

    public Employee(String Name, int age)
    {
        this.Name = Name;
        this.age = age;
    }
    public string EmpName
    {
        get { return Name; }
    }
}
Community
  • 1
  • 1
raj
  • 71
  • 7
  • As an aside, Name should really be a private field. And does CreateInstance actually pass the data via the constructor? – David L Apr 23 '16 at 03:09
  • I am new to specflow. How to pass values with CreateInstance in specflow? – raj Apr 23 '16 at 04:35

3 Answers3

1

CreateInstance will only set public values because that it is all it can access.

Darren
  • 987
  • 5
  • 6
0

Like this:

[Binding]
public class TableSteps
{
    [Given(@"below employee create a user\.")]
    public void GivenBelowEmployeeCreateAUser_(Table table)
    {
        Employee employee = new Employee(table.Rows[0][0], int.Parse(table.Rows[0][1]));
        Console.Write("Name:" + employee.Name); //Works as it is public.
        Console.Write("Name:"+ employee.EmpName); //No value returned here. Just null.
    }
}

you could wrap this into an extension method if you want to have it a bit more readable, something like.

Employee employee = table.CreateEmployee();

but if you want a generic solution then you'll have to write one your self.

it shouldn't be too hard though, just create an extension method like CreateInstance that takes a param array of objects, and then reflect over the constructors of the type you are creating to find the constructor which has the same number of params as the method was invoked with and invoke that constructor using the passed parameters.

If these classes are just for testing I would make them public though as this is the easiest solution.

Sam Holder
  • 32,535
  • 13
  • 101
  • 181
0

This is similar to SpecFlow and complex objects in that you can create a class that acts as a "view model" for your SpecFlow table:

public class EmployeeRow
{
    public string Name { get; set; }
    public int Age { get; set; }

    public Employee ToEmployee()
    {
        return new Employee(Name, Age);
    }
}

Then in your step definition:

[Given(@"below employee create a user\.")]
public void GivenBelowEmployeeCreateAUser_(Table table)
{
    Employee employee = table.CreateInstance<EmployeeRow>().ToEmployee();
    Console.Write("Name:" + employee.Name);
    Console.Write("Name:"+ employee.EmpName);
}
Community
  • 1
  • 1
Greg Burghardt
  • 17,900
  • 9
  • 49
  • 92