C# xUnit Test listeners C# xUnit Test listeners selenium selenium

C# xUnit Test listeners


I haven't worked with TestNG, but I did some quick reading and I think I see what you're after.

To demonstrate, I've implemented a very basic proof-of-concept xUnit IMessageSink.

public class MyMessageSink : IMessageSink{    public bool OnMessage(IMessageSinkMessage message)    {        // Do what you want to in response to events here.        //         // Each event has a corresponding implementation of IMessageSinkMessage.        // See examples here: https://github.com/xunit/abstractions.xunit/tree/master/src/xunit.abstractions/Messages        if (message is ITestPassed)        {            // Beware that this message won't actually appear in the Visual Studio Test Output console.            // It's just here as an example. You can set a breakpoint to see that the line is hit.            Console.WriteLine("Execution time was an awesome " + ((ITestPassed)message).ExecutionTime);        }        // Return `false` if you want to interrupt test execution.        return true;    }}

The sink is then registered via an IRunnerReporter:

public class MyRunnerReporter : IRunnerReporter{    public string Description => "My custom runner reporter";    // Hard-coding `true` means this reporter will always be enabled.    //    // You can also implement logic to conditional enable/disable the reporter.    // Most reporters based this decision on an environment variable.    // Eg: https://github.com/xunit/xunit/blob/cbf28f6d911747fc2bcd64b6f57663aecac91a4c/src/xunit.runner.reporters/TeamCityReporter.cs#L11    public bool IsEnvironmentallyEnabled => true;    public string RunnerSwitch => "mycustomrunnerreporter";    public IMessageSink CreateMessageHandler(IRunnerLogger logger)    {        return new MyMessageSink();    }}

To use my example code, just copy the classes into your test project (you'll also need to add a reference to the xunit.runner.utility NuGet package). The xUnit framework will automagically discover the IRunnerReporter--no need to explicitly register anything.

If this seems like it's headed in the right direction, you can find a lot more info in the xUnit source code. All of the interfaces involved are well-documented. There are a few existing implementations in the xunit.runner.reporters namespace. AssemblyRunner.cs also demonstrates one possible method for dispatching the different event types to individual handlers.

Edit 1

I've updated the implementation of MyMessageSink (above) to demonstrate how you might listen for an ITestPassed message. I also updated the link embedded in that code snippet--the previous link was to implementations, but we should really use these abstractions.

The if (message is IMessageType) pattern is pretty crude, and won't scale well if you want to listen for many different message types. Since I don't know your needs, I just went with the simplest thing that could possibly work--hopefully it's enough that you can improve/extend it to fit your needs.