xUnit lacks useful functionalities, but the strength of a good framework is that one can easily implement needed features. Today I would like to present two examples, that I found useful in everyday work.
Repeating tests
There are different opinions on non-deterministic tests, some say that it is the rule that the tests should always have the same results, but for me, random seed for data in tests is an opportunity to find edge cases, that we haven't considered. It's one step closer to property testing known from QuickCheck. When I worked in NUnit I used RepeatAttribute
for this, in xUnit there is no builtin, so we can provide it on our own.
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class RepeatAttribute : DataAttribute
{
private readonly int _count;
public RepeatAttribute(int count)
{
if (count < 1)
{
throw new ArgumentOutOfRangeException(nameof(count),
"Repeat count must be greater than 0.");
}
_count = count;
}
public override IEnumerable<object[]> GetData(MethodInfo testMethod)
{
return Enumerable.Repeat(Array.Empty<object>(), _count);
}
}
Timeout
Tests usually should be fast, but occasionally bugs that cause tests to hang up are introduced. Even worse if it occurs not locally, but in CI pipeline - we block the worker for no reason, instead of failing fast. For this case, where in NUnit we could use TimeoutAttribute
, in xUnit there already is such an option available inside FactAttribute
(and TheoryAttribute
that inherits from it).
[Fact(Timeout = 1000)]
public async Task LongRunningTest()
{
await Task.Delay(2000);
}