Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda expression as inline data in xUnit

I'm pretty new to xUnit and here's what I'd like to achieve:

[Theory]
[InlineData((Config y) => y.Param1)]
[InlineData((Config y) => y.Param2)]
public void HasConfiguration(Func<Config, string> item)
{
    var configuration = serviceProvider.GetService<GenericConfig>();
    var x = item(configuration.Config1); // Config1 is of type Config

    Assert.True(!string.IsNullOrEmpty(x));            
}

Basically, I have a GenericConfig object which contains Config and other kind of configurations, but I need to check that every single parameter is valid. Since they're all string, I wanted to simplify using [InlineData] attribute instead of writing N equals tests.

Unfortunately the error I'm getting is "Cannot convert lambda expression to type 'object[]' because it's not a delegate type", which is pretty much clear.

Do you have any idea on how to overcome this?

like image 937
xTuMiOx Avatar asked Jul 25 '17 09:07

xTuMiOx


2 Answers

In addition to the already posted answers. The test cases can be simplified by directly yielding the lambdas.

public class ConfigTestDataProvider
{
    public static IEnumerable<object[]> TestCases
    {
        get
        {
            yield return new object [] { (Func<Config, object>)((x) => x.Param1) };
            yield return new object [] { (Func<Config, object>)((x) => x.Param2) };
        }
    }
}

This test ConfigTestDataProvider can then directly inject the lambdas.

[Theory]
[MemberData(nameof(ConfigTestCase.TestCases), MemberType = typeof(ConfigTestCase))]
public void Test(Func<Config, object> func)
{
    var config = serviceProvider.GetService<GenericConfig>();
    var result = func(config.Config1);

    Assert.True(!string.IsNullOrEmpty(result));
}
like image 67
Iqon Avatar answered Oct 05 '22 23:10

Iqon


Actually, I was able to find a solution which is a bit better than the one provided by Iqon (thank you!).

Apparently, the InlineData attribute only supports primitive data types. If you need more complex types, you can use the MemberData attribute to feed the unit test with data from a custom data provider.

Here's how I solved the problem:

public class ConfigTestCase
{
    public static readonly IReadOnlyDictionary<string, Func<Config, string>> testCases = new Dictionary<string, Func<Config, string>>
    {
        { nameof(Config.Param1), (Config x) => x.Param1 },
        { nameof(Config.Param2), (Config x) => x.Param2 }
    }
    .ToImmutableDictionary();

    public static IEnumerable<object[]> TestCases
    {
        get
        {
            var items = new List<object[]>();

            foreach (var item in testCases)
                items.Add(new object[] { item.Key });

            return items;
        }
    }
}

And here's the test method:

[Theory]
[MemberData(nameof(ConfigTestCase.TestCases), MemberType = typeof(ConfigTestCase))]
public void Test(string currentField)
{
    var func = ConfigTestCase.testCases.FirstOrDefault(x => x.Key == currentField).Value;
    var config = serviceProvider.GetService<GenericConfig>();
    var result = func(config.Config1);

    Assert.True(!string.IsNullOrEmpty(result));
}

I could maybe come up with something a bit better or cleaner, but for now it works and the code is not duplicated.

like image 30
xTuMiOx Avatar answered Oct 06 '22 00:10

xTuMiOx