Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xunit 2.3.0 Unable to pass dates as inline params

In xUnit 2.2 and prior versions, we were able to pass date strings as inline data when implementing a Theory.

[Theory]
[InlineData("title 1", "testing 1", 1, "Educational", "2017-3-1", "2018-12-31")]
[InlineData("title 2", "testing 2", 2, "Self Employment", "2017-2-1", "2018-2-28")]
public async Task WhenPassingCorrectData_SuccessfullyCreate(
    string title,
    string description,
    int categoryId,
    string category,
    DateTime startDate,
    DateTime endDate)
{

}

But with 2.3 update this seems to be broken and Visual studio is giving a compile error.

The value is not convertible to the method parameter 'startDate' of type 'System.DateTime

Has anyone got a workaround for this other that having to receive dates as strings and cast them inside the test method?

And would this be a temporary bug in this version and will be fixed in future version?

PS: I'm using xUnit on a .netcore project on VS2017

like image 888
Wijitha Avatar asked Dec 15 '17 08:12

Wijitha


4 Answers

You can make it explicit with MemberDataAttribute :-

public static readonly object[][] CorrectData =
{
    new object[] { "title 1", "testing 1", 1, "Educational", new DateTime(2017,3,1), new DateTime(2018,12,31)},
    new object[] { "title 2", "testing 2", 2, "Self Employment", new DateTime(2017, 2, 1), new DateTime(2018, 2, 28)}
};

[Theory, MemberData(nameof(CorrectData))]
public async Task WhenPassingCorrectData_SuccessfullyCreate(string title, string description, int categoryId, string category, DateTime startDate, DateTime endDate)
{

}

(You can also make the property return IEnumerable<object[]>, which you'd typically do with yield return enumerator syntax, but I believe the above is the most legible syntax C# has to offer for it at present)

like image 121
Ruben Bartelink Avatar answered Nov 08 '22 20:11

Ruben Bartelink


The better way to do it currently is to use TheoryData so that you can use strongly typed inputs. Creating strongly typed xUnit theory test data with TheoryData

TheoryData<DateTime> MemberData = new TheoryData<DateTime>
{
 DateTime.Now, 
 new DateTime(), 
 DateTime.Max
}
like image 20
Rohit Vipin Mathews Avatar answered Nov 08 '22 19:11

Rohit Vipin Mathews


It appears that this bug is fixed in v2.4.0+ (this feature stopped working in at least v2.3.1?)

If unable to upgrade xunit to a version with the fix then perhaps do the equivalent of what xunit is doing implicitly:

https://github.com/xunit/xunit/blob/07457dab8d0bb188e74e476c062a4a9aeca44711/src/xunit.v3.common/Reflection/Reflector.cs#L88-L92

[Theory]
[InlineData("title 1", "testing 1", 1, "Educational", "2017-3-1", "2018-12-31")]
[InlineData("title 2", "testing 2", 2, "Self Employment", "2017-2-1", "2018-2-28")]
public async Task WhenPassingCorrectData_SuccessfullyCreate(
    string title,
    string description,
    int categoryId,
    string category,
    string startDate, // <-- change from `DateTime` to `string`
    string endDate)   // <-- change from `DateTime` to `string`
{
    var expectedStartDate = DateTime.Parse(startDate); // <-- add this
    var expectedEndDate = DateTime.Parse(endDate);     // <-- add this

    //  rest of test ...

}

Otherwise if have more complicated tests then perhaps use MemberDataAttribute as others suggested.

like image 5
Ray Avatar answered Nov 08 '22 20:11

Ray


Here is a good way to pass strongly typed test data in to xUnit Tests

Blog Post

Source Code

public class SampleData
{
    public int A { get; set; }
    public int B { get; set; }
    public int C => A + B;
}

public class UnitTest1
{
    /// <summary>
    /// The test data must have this return type and should be static
    /// </summary>
    public static IEnumerable<object[]> TestData
    {
        get
        {
            //Load the sample data from some source like JSON or CSV here.
            var sampleDataList = new List<SampleData>
            {
                new SampleData { A = 1, B = 2 },
                new SampleData { A = 3, B = 2 },
                new SampleData { A = 2, B = 2 },
                new SampleData { A = 3, B = 23 },
                new SampleData { A = 43, B = 2 },
                new SampleData { A = 3, B = 22 },
                new SampleData { A = 8, B = 2 },
                new SampleData { A = 7, B = 25 },
                new SampleData { A = 6, B = 27 },
                new SampleData { A = 5, B = 2 }
         };

            var retVal = new List<object[]>();
            foreach(var sampleData in sampleDataList)
            {
                //Add the strongly typed data to an array of objects with one element. This is what xUnit expects.
                retVal.Add(new object[] { sampleData });
            }
            return retVal;
        }
    }

/* Alternate form

    public static IEnumerable<object[]> TestData() 
    {
        yield return new [] { new SampleData { A = 1, B = 2 } };
        yield return new [] { new SampleData { A = 3, B = 2 } };
        yield return new [] { new SampleData { A = 2, B = 2 } };
        yield return new [] { new SampleData { A = 3, B = 23 } };
        yield return new [] { new SampleData { A = 43, B = 2 } };
        yield return new [] { new SampleData { A = 3, B = 22 } };
        yield return new [] { new SampleData { A = 8, B = 2 } };
        yield return new [] { new SampleData { A = 7, B = 25 } };
        yield return new [] { new SampleData { A = 6, B = 27 } };
        yield return new [] { new SampleData { A = 5, B = 2 } };
    }
*/

/* Or:

    public static IEnumerable<object[]> TestData() =>
        from x in new[] { 
            new SampleData { A = 1, B = 2 },
            new SampleData { A = 3, B = 2 },
            new SampleData { A = 2, B = 2 },
            new SampleData { A = 3, B = 23 },
            new SampleData { A = 43, B = 2 },
            new SampleData { A = 3, B = 22 },
            new SampleData { A = 8, B = 2 },
            new SampleData { A = 7, B = 25 },
            new SampleData { A = 6, B = 27 },
            new SampleData { A = 5, B = 2 } }
        select new object[] { x};
    */

    /// <summary>
    /// Specify the test data property with an attribute. This method will get executed 
    /// for each SampleData object in the list
    /// </summary>
    [Theory, MemberData(nameof(TestData))]       
    public void Test1(SampleData sampleData)
    {
        Assert.Equal(sampleData.A + sampleData.B, sampleData.C);
    }
}
like image 5
Christian Findlay Avatar answered Nov 08 '22 19:11

Christian Findlay