Search code examples
c#visual-studiocsvnunittest-explorer

Use a column name (from a CSV file) as the name of a test using Nunit


I am trying to use a column value as the name of tests in order for all rows to display in the Test Explorer pane in Visual Studio on a per row basis.

The following is what would be my test that consumes the data from the CSV file. I tried using the "TestName" attribute and slicing ("{15:16}") the default name for the section of the string that I'd like to use as the test name. I am definitely now doing it correctly because it's just giving me the name of the method name.

The second method is my read operation. Additionally, I don't like having to assign my data to variables and then have to pass them. I am really looking for a more elegant way to solve reading and using CSV data for naming and testing so if anyone has any experience or thoughts I would love to hear them.

Please let me know if I've left any information out that would further clarify my goal.

class MegaTests
{
    [TestCase(TestName = "{15:16}")]
    [Test, TestCaseSource("GetTestData")]
    public void MyExample_Test(string TestName, string json, string ExpectedResult, string Environment, string ChannelMessage, string ChannelSubject, string MessageCenterMessage, string MessageCenterSubject)
    {
        Console.WriteLine(TestName + " " + json + " " + ExpectedResult + " " + Environment + " " + ChannelMessage + " " + ChannelSubject + " " + MessageCenterMessage + " " + MessageCenterSubject);

    }

private static IEnumerable<string[]> GetTestData()
    {
        //using (var csv = new CsvReader(new StreamReader(@"../../csv/data.csv"), true))
        using (var csv = new CsvReader(new StreamReader(@"DataDriveFromCSV/csv/data.csv"), true))
        {
            while (csv.ReadNextRecord())
            {
                string TestName = csv[0];
                string json = csv[1];
                string ExpectedResult = csv[2];
                string Environment = csv[3];
                string ChannelMessage = csv[4];
                string ChannelSubject = csv[5];
                string MessageCenterMessage = csv[6];
                string MessageCenterSubject = csv[7];

                yield return new[] { TestName, json, ExpectedResult, Environment, ChannelMessage, ChannelSubject, MessageCenterMessage, MessageCenterSubject };
            }
        }
    }

Solution

  • [TestCase] and [TestCaseSource] are alternative, orthogonal approaches to getting data to your tests. They don't cooperate in any way although you can use both to get data in two different ways.

    If you use [TestCase(TestName="{15:16}")], you are creating a test with no arguments and a name of "{15:16}". Using TestCaseSource is the proper way to do what you want to do.

    If you think it through, you'll realize you can't pass the name of a test as an argument to the test. The test has to exist to call it in the first place and once it exists it already has a name.

    Instead of returning an array of arguments, you should return an instance of TestCaseData, which will allow you to pass arguments as well as set the name of the test.