TL;DR - I\'m looking for xUnit\'s equivalent of MSTest\'s AssemblyInitialize (aka the ONE feature it has that I like).
Specifically I\'m looking for it
I was quite annoyed for not having the option to execute things at the end of all the xUnit tests. Some of the options here are not as great, as they involve changing all your tests or putting them under one collection (meaning they get executed synchronously). But Rolf Kristensen's answer gave me the needed information to get to this code. It's a bit long, but you only need to add it into your test project, no other code changes necessary:
using Siderite.Tests;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
[assembly: TestFramework(
SideriteTestFramework.TypeName,
SideriteTestFramework.AssemblyName)]
namespace Siderite.Tests
{
public class SideriteTestFramework : ITestFramework
{
public const string TypeName = "Siderite.Tests.SideriteTestFramework";
public const string AssemblyName = "Siderite.Tests";
private readonly XunitTestFramework _innerFramework;
public SideriteTestFramework(IMessageSink messageSink)
{
_innerFramework = new XunitTestFramework(messageSink);
}
public ISourceInformationProvider SourceInformationProvider
{
set
{
_innerFramework.SourceInformationProvider = value;
}
}
public void Dispose()
{
_innerFramework.Dispose();
}
public ITestFrameworkDiscoverer GetDiscoverer(IAssemblyInfo assembly)
{
return _innerFramework.GetDiscoverer(assembly);
}
public ITestFrameworkExecutor GetExecutor(AssemblyName assemblyName)
{
var executor = _innerFramework.GetExecutor(assemblyName);
return new SideriteTestExecutor(executor);
}
private class SideriteTestExecutor : ITestFrameworkExecutor
{
private readonly ITestFrameworkExecutor _executor;
private IEnumerable _testCases;
public SideriteTestExecutor(ITestFrameworkExecutor executor)
{
this._executor = executor;
}
public ITestCase Deserialize(string value)
{
return _executor.Deserialize(value);
}
public void Dispose()
{
_executor.Dispose();
}
public void RunAll(IMessageSink executionMessageSink, ITestFrameworkDiscoveryOptions discoveryOptions, ITestFrameworkExecutionOptions executionOptions)
{
_executor.RunAll(executionMessageSink, discoveryOptions, executionOptions);
}
public void RunTests(IEnumerable testCases, IMessageSink executionMessageSink, ITestFrameworkExecutionOptions executionOptions)
{
_testCases = testCases;
_executor.RunTests(testCases, new SpySink(executionMessageSink, this), executionOptions);
}
internal void Finished(TestAssemblyFinished executionFinished)
{
// do something with the run test cases in _testcases and the number of failed and skipped tests in executionFinished
}
}
private class SpySink : IMessageSink
{
private readonly IMessageSink _executionMessageSink;
private readonly SideriteTestExecutor _testExecutor;
public SpySink(IMessageSink executionMessageSink, SideriteTestExecutor testExecutor)
{
this._executionMessageSink = executionMessageSink;
_testExecutor = testExecutor;
}
public bool OnMessage(IMessageSinkMessage message)
{
var result = _executionMessageSink.OnMessage(message);
if (message is TestAssemblyFinished executionFinished)
{
_testExecutor.Finished(executionFinished);
}
return result;
}
}
}
}
The highlights:
More work could be done here. If you want to execute stuff without caring about the tests run, you could inherit from XunitTestFramework and just wrap the message sink.