xUnit is the latest framework for unit tests in .NET projects, including .NET Core.
However, comparing to nUnit, xUnit is still missing a lot o functionalities helpful for automated tests on higher level than unit tests. In this article I will describe a workaround for one of missing features – access to current test method name. Unfortunately, xUnit does not provided TextContext or equivalent so it needs to be implemented separately. There are few solutions available but most suitable for my needs is using custom attribute.
Start with creating new custom attribute e.g. AddContextAttribute.cs
using System.Reflection;
using Xunit.Sdk;
namespace QaServices.Attributes
{
public class TakeScreenshotAttribute : BeforeAfterTestAttribute
{
public override void Before(MethodInfo methodInfo)
{
}
public override void After(MethodInfo methodInfo)
{
}
}
}
Note that your new attribute is derived from xUnit BeforeAfterTestAttribute and overrides two methods: Before which will be run before TestMethod annotated with this attribute and After which will be run just after Test Method.
Execution sequence regarding BaseTest constructor and dispose is as following:
- BaseTest constructor
- AddContextAttribute.Before method
- AddContextAttribute.After method
- BaseTest.Dispose method
In AddContextAttribute we have access to TestMethod name. To have access to it from other parts of test solution, it needs to be passed to some static class.
Let`s create static class TestContext with variable for storing test name:
public static class TestContext
{
public static string CurrentTestName;
}
Now add code that passes MethodName to TestContext
public override void Before(MethodInfo methodInfo)
{
TestContext.CurrentTestName = methodInfo.Name;
}
Last thing is to mark your tests with AddContext attribute e.g.
public class Tests
{
[Fact, AddContext]
public void Test()
{
}
}
Now, TestContext.CurrentTestName can be accessed from any class in the project and used for logging, screenshot names etc.
Example of usage:
public class BaseTest : IDisposable
{
private readonly IWebDriver _webDriver;
public BaseTest()
{
// initializing _webDriver
}
public void Dispose()
{
_webDriver.SaveScreenshot($"{TestContext.CurrentTestName}.png");
}
}