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
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)
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
}
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.
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With