So I was limited to a specific version of NUnit for various reasons, and needed to start being able to run ‘core’ tests, so I migrated to XUnit. Generally not a problem until I hit ‘SetupFixture’. XUnit has no concept of ‘SetupFixture’ and from what I can gather, won’t either (https://github.com/xunit/xunit/issues/111).
So, in order to get the same approach, I need to implement ‘IClassFixture’ on every test class. I could do this by going through each 1 by 1, but then how can I ensure that another developer (or even me!) remembers to do it the next time? For example, creating a new test class. In fact the reason for the SetupFixture was entirely because you can’t assume someone will derive or implement an interface.
In the end, I took the approach of adding another test to my code to ‘test the tests’ ensuring that each test class implemented IClassFixture. The code is below, tweak to your own needs!
[Fact]
public void AllClassesImplementIUseFixture()
{
var typesWithFactsNotImplementingIClassFixture =
//Get this assembly and it's types.
Assembly.GetExecutingAssembly().GetTypes()
//Get the types with their interfaces and methods
.Select(type => new {type, interfaces = type.GetInterfaces(), methods = type.GetMethods()})
//First we only want types where they have a method which is a 'Fact'
.Where(t => t.methods.Select(Attribute.GetCustomAttributes).Any(attributes => attributes.Any(a => a.GetType() == typeof(FactAttribute))))
//Then check if that type implements the type
.Where(t => t.interfaces.All(i => i != typeof(IClassFixture)))
//Select the name
.Select(t => t.type.FullName)
.ToList();
if (typesWithFactsNotImplementingIClassFixture.Any())
throw new InvalidOperationException(
$"All test classes must implement {nameof(IClassFixture<OriginalSetupFixture>)}{Environment.NewLine}These don't:{Environment.NewLine} * {string.Join($"{Environment.NewLine} * ", typesWithFactsNotImplementingIClassFixture)}");
}
