How to implement test data in JSON file in data-driven unit test in .NET using C#
Asked Answered
A

1

5

I was doing unit test using xUnit package for my class library. I would like to try on JSON approach rather than normal object approach for data-driven unit test. However I don't see anywhere that able to achieve this.

What I am stucking at is data-driven test MemberData require the test data to be present in IEnumerable<object[]> type, when I call data from JSON file, it is in my data model class typed. Do I add them into the IEnumerable<object[]>? Or there is another way to do it?

Here's the code I have so far:

This is the json file which holds 5 test data:

{
  "user": [
    {
      "name": "John",
      "age": 12,
      "gender": "Male",
      "Hobby": "Reading"
    },
    {
      "name": "Susan",
      "age": 34,
      "gender": "Female",
      "Hobby": "Gardening"
    },
    {
      "name": "Larry",
      "age": 24,
      "gender": "Male",
      "Hobby": "Gaming"
    },
    {
      "name": "Jack",
      "age": 3,
      "gender": "Male",
      "Hobby": "Sleeping"
    },
    {
      "name": "Minnie",
      "age": 15,
      "gender": "Female",
      "Hobby": "Partying"
    }
  ]
}

This is Test class file:

private User GetTestData()
{
     var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestData.json"); 
     var reader = new StreamReader(filePath);
     var jsonStr = reader.ReadToEnd();
     var jsonObj = JObject.Parse(jsonStr);

     var testDataObj = jsonObj["user"].ToString();
     var testData = JsonConvert.DeserializeObject<User>(testDataObj);

     return testData;
}

public static IEnumerable<object[]> ValidUserTestData()
{
     //What should I do here?   
}

[Theory]
[MemberData(nameof(ValidUserTestData))]
public void Test1()
{

}

Is this the correct way to implement this type of test? Or is there any other better options to use JSON file inside data-drive test?

Thank you.

Acanthous answered 1/3, 2020 at 8:37 Comment(0)
A
11

MemberData attribute accepts an IEnumerable<object[]> of objects, which will be passed to your test method one by one. So, you should deserialize your JSON into array of objects (your json sample contains an array of User objects), and then return it from ValidUserTestData method. Also make sure, that Test1() accepts a correct parameter

[Theory]
[MemberData(nameof(ValidUserTestData))]
public void Test1(User user)
{
    //test logic against every User instance
}

ValidUserTestData can be declared per following: read the json first, than convert it to the enumeration of User objects and return it as an IEnumerable<object[]>

public static IEnumerable<object[]> ValidUserTestData()
{
    var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestData.json");
    var json = File.ReadAllText(filePath);
    var jobject = JObject.Parse(json);
    var users = jobject["user"]?.ToObject<IEnumerable<User>>();

    foreach (var user in users ?? Enumerable.Empty<User>())
    {
        yield return new[] { user };
    }
}

Every single item in IEnumerable<object[]> represents an set of parameters, accepted by the test method. You'll need only one input parameter in your test method, so every object[] contains single user instance.

There is very nice article about it Creating parameterized tests in xUnit

Asymmetric answered 1/3, 2020 at 8:47 Comment(2)
Note 1: Had to use the "Copy to Output Directory" file property settings set to "Copy Always" for this to work.Everyway
Note 2: if you're able to use System.Text.Json, you can simply do return JsonSerializer.Deserialize<IEnumerable<User>>(json); ... i.e. no need for the JObject, the ToObject method call, nor the foreach. Yes, you'll get a JsonReaderException if the file is empty, but this is a static xUnit file, it probably doesn't make sense for it to be empty anyway.Everyway

© 2022 - 2024 — McMap. All rights reserved.