Test Context
All tests have a TestContext object available to them.
This can be accessed statically via TestContext.Current.
Here you can see information about the test, including things like the test name, containing class, custom properties, categories, etc.
This can be useful if you want something like a generic AfterEachTest for all tests, but with logic to execute for only certain tests.
e.g.
if (TestContext.Current?.Metadata.TestDetails.CustomProperties.ContainsKey("SomeProperty") == true)
{
// Do something
}
The context also has a Results object. You'll notice this is nullable. This will be null until you're in the context of a AfterEachTest method. That's because the Results can only be set after a test has finished.
These results can be handy when you're cleaning up, but maybe only want to do something if a test failed.
e.g.
if (TestContext.Current?.Result?.State == TestState.Failed)
{
// Take a screenshot?
}
Test Output and Artifactsâ
The TestContext provides multiple ways to write output and attach artifacts:
// Write to standard output (modern interface-based approach)
TestContext.Current!.Output.WriteLine("Debug information");
// Alternative: Direct TextWriter access (also valid)
TestContext.Current!.OutputWriter.WriteLine("Debug information");
// Write to error output
TestContext.Current.Output.WriteError("Warning: something unexpected happened");
// Attach an artifact (file, screenshot, log, etc.)
TestContext.Current.Output.AttachArtifact(new Artifact
{
File = new FileInfo("path/to/logfile.log"),
DisplayName = "Application Logs",
Description = "Logs captured during test execution"
});
Both Output.WriteLine() and OutputWriter.WriteLine() are valid - the Output property provides a convenient interface-based API, while OutputWriter gives direct access to the underlying TextWriter.
Artifacts are particularly useful for debugging test failures, especially in integration tests. You can attach screenshots, logs, videos, configuration files, or any other files that help diagnose issues.
For complete information about working with test artifacts, including session-level artifacts, best practices, and common use cases, see the Test Artifacts guide.
Dependency Injectionâ
Note: TestContext does NOT provide direct access to dependency injection services. The internal service provider in TestContext is exclusively for TUnit framework services and is not meant for user-provided dependencies.
If you need dependency injection in your tests, use the DependencyInjectionDataSourceAttribute<TScope> helper class to set up your own DI container. See the Dependency Injection guide for complete details and examples.
TestBuilderContextâ
In addition to TestContext, TUnit also provides TestBuilderContext which is available during the test discovery and building phase. This is particularly useful when you need context information in data generators or other scenarios that run before test execution.
When to Use TestBuilderContext vs TestContextâ
Use TestBuilderContext.Current when:
- Writing data generators that need test information
- During test discovery phase
- In scenarios that run before
TestContextis available - When you need to pass data from discovery time to execution time
Use TestContext.Current when:
- During test execution
- In test methods, Before/After hooks
- When you need test results or execution-specific information
- When accessing test output writers
Accessing TestBuilderContextâ
public static IEnumerable<object[]> MyDataGenerator()
{
var context = TestBuilderContext.Current;
if (context != null)
{
// Access test information during data generation
Console.WriteLine($"Generating data for: {context.TestMethodName}");
Console.WriteLine($"Test class: {context.ClassInformation?.Type.Name}");
Console.WriteLine($"Assembly: {context.ClassInformation?.Assembly.Name}");
// Store data for later use during test execution
context.StateBag["GenerationTime"] = DateTime.Now;
}
yield return new object[] { 1, 2, 3 };
}
Sharing Data Between Discovery and Executionâ
The StateBag property on TestBuilderContext is carried forward to TestContext, allowing you to pass data from discovery time to execution time:
// In your data generator
public static IEnumerable<object[]> TestData()
{
var builderContext = TestBuilderContext.Current;
if (builderContext != null)
{
builderContext.StateBag["DataGeneratedAt"] = DateTime.Now;
builderContext.StateBag["GeneratorVersion"] = "1.0";
}
yield return new object[] { "test" };
}
// In your test
[Test]
[MethodDataSource(nameof(TestData))]
public void MyTest(string value)
{
// Access the data stored during generation
var generatedAt = TestContext.Current.StateBag["DataGeneratedAt"];
var version = TestContext.Current.StateBag["GeneratorVersion"];
Console.WriteLine($"Data was generated at: {generatedAt}");
}
Available Propertiesâ
TestBuilderContext provides:
TestMethodName- The name of the test method being builtClassInformation- Full information about the test class including:Type- The test class typeAssembly- Assembly informationNamespace- The namespace- Properties, parameters, and more
MethodInformation- Full information about the test methodStateBag- A dictionary for storing custom dataEvents- Test events that can be subscribed to
Note: TestBuilderContext.Current will be null if accessed outside of test discovery/building phase.