Search code examples
listparametersxunittestcase

XUnit MemberData with List objects


I am writing a xunit test to test the functionality of a utility method that splits a sentence based on spaces. Ex: Input: "Who goes there?", Output: {"Who", "goes", "there"} a collection/list of strings.

I have attempted the following

    [Theory]
    [MemberData(nameof(GetSplitWordHelperTestCases))]
    public void TestSplitWord(TestSplitWordHelper splitWordHelper)
    {
        var actualResult = (List<string>)splitWordHelper.Build().Item1.SplitWord();
        var expectedResult = (List<string>)splitWordHelper.Build().Item2;
        Assert.Equal(expectedResult.Count, actualResult.Count);

        for(int i = 0; i < actualResult.Count; i++)
        {
            Assert.Equal(expectedResult[i], actualResult[i]);
        }
    }

    public static IEnumerable<object[]> GetSplitWordHelperTestCases()
    {
        yield return new object[] { new TestSplitWordHelper("Hi There", 
new List<string> { "Hi", "There" }) };
    }

    public class TestSplitWordHelper : IXunitSerializable
    {
        private IEnumerable<string> results;
        private string source;

        public TestSplitWordHelper()
        {

        }

        public TestSplitWordHelper(string source, IEnumerable<string> results)
        {
            this.source = source;
            this.results = results;
        }

        public Tuple<string, IEnumerable<string>> Build()
        {
            return new Tuple<string, IEnumerable<string>>(source, this.results);
        }
        public void Deserialize(IXunitSerializationInfo info)
        {
            source = info.GetValue<string>("source");
            results = info.GetValue<IEnumerable<string>>("results");
        }

        public void Serialize(IXunitSerializationInfo info)
        {
            info.AddValue("source", source, typeof(string));
            info.AddValue("results", results, typeof(IEnumerable<string>));
        }

        public override string ToString()
        {
            return string.Join(" ", results.Select(x => x.ToString()).ToArray());
        }
    }

When I compile this I am getting "System.ArgumentException: We don't know how to serialize type System.Collections.Generic.List" and I understand this issue. Xunit cannot serialize List.

Given my use case, how do I write the test cases?

Thanks!


Solution

  • Xunit cannot serialize List.

    The trick would to switch to arrays. Indeed, Xunit supports this.

    As such switch all IEnumerable<string> and List<string> into string[]... and tada! It works.

    Below a patched and tested version of your code (changes that have been applied are decorated with comments).

    [Theory]
    [MemberData(nameof(GetSplitWordHelperTestCases))]
    public void TestSplitWord(TestSplitWordHelper splitWordHelper)
    {
        var actualResult = splitWordHelper.Build().Item1.SplitWord().ToList();
    
        // (List<string>) changed to new List<string(...)
        var expectedResult = new List<string>(splitWordHelper.Build().Item2);
        Assert.Equal(expectedResult.Count, actualResult.Count);
    
        for (int i = 0; i < actualResult.Count; i++)
        {
            Assert.Equal(expectedResult[i], actualResult[i]);
        }
    }
    
    public static IEnumerable<object[]> GetSplitWordHelperTestCases()
    {
        yield return new object[] { new TestSplitWordHelper("Hi There",
    
          // new List<string> changed to new string[]
          new string[] { "Hi", "There" }) };
    }
    
    public class TestSplitWordHelper : IXunitSerializable
    {
        private string[] results;
        private string source;
    
        public TestSplitWordHelper()
        {
    
        }
    
        public TestSplitWordHelper(string source, string[] results)
        {
            this.source = source;
            this.results = results;
        }
    
        public Tuple<string, string[]> Build()
        {
            return new Tuple<string, string[]>(source, results);
        }
        public void Deserialize(IXunitSerializationInfo info)
        {
            source = info.GetValue<string>("source");
    
            // IEnumerable<string> changed to string[]
            results = info.GetValue<string[]>("results");
        }
    
        public void Serialize(IXunitSerializationInfo info)
        {
            info.AddValue("source", source, typeof(string));
    
            // IEnumerable<string> changed to string[]
            info.AddValue("results", results, typeof(string[]));
        }
    
        public override string ToString()
        {
            return string.Join(" ", results.Select(x => x.ToString()).ToArray());
        }
    }