NUnit & lifecycle

Introduction

CSTesting for .NET (C:\CSTesting-DotNet) is meant to be used with NUnit. You structure tests with [TestFixture], [SetUp], [TearDown], [OneTimeSetUp], [OneTimeTearDown], and [Test] as usual. The CSTesting library adds CSTestingTestBase (a Browser property) and optionally CSTestingNUnitBrowserFixtureBase, which closes Playwright after each test and supports pause-on-failure. Nothing injects a browser automatically—you call CreateBrowserAsync yourself (see SampleRecordedTest.cs in the repo).

NUnit and CSTesting attributes

AttributeRole
[TestFixture]Marks a class that contains tests.
[SetUp]Runs before each [Test] — typical place to CreateBrowserAsync and assign Browser.
[TearDown]Runs after each test. If you use CSTestingNUnitBrowserFixtureBase, do not add a second tear-down that closes the browser (the base handles it).
[Test]Async test method; use await Browser!.GotoAsync(...), etc.
[Test(Description = "...")]Human-readable description in runners and reports.
[CSTestingTag("smoke")]Maps to NUnit category smoke for dotnet test --filter TestCategory=smoke (CSTestingTagAttribute.cs).
[Category("smoke")]Standard NUnit category; same filtering idea.

Execution order

NUnit runs one-time setup/teardown for the fixture, then for each test: [SetUp][Test][TearDown]. Whether you share one browser across tests or create a new browser per test is your choice; the sample uses one browser per test via [SetUp] and closes it in the fixture base [TearDown].

Base classes

TypeDescription
CSTestingTestBaseExposes protected ICSTestingBrowser? Browser { get; set; }. You assign it after CreateBrowserAsync.
CSTestingNUnitBrowserFixtureBaseExtends the above; adds [TearDown] that optionally pauses on failure (env vars) then await Browser.CloseAsync().

Headed browser:

Browser = await CreateBrowserAsync(new CSTestingOptions { Headless = false });

[Test] example

[Test]
public async Task Login_RedirectsToWelcome()
{
    await Browser!.GotoAsync("https://example.com/login");
    await Browser.TypeAsync("name=user", "alice");
    await Browser.ClickAsync("button[type=submit]");
    await Browser.WaitForURLAsync("**/welcome", 10_000);
}

[Test(Description = "Check example.com heading")]
public async Task Example_HasHeading()
{
    await Browser!.GotoAsync("https://example.com");
    var text = await Browser.Locator("h1").GetTextContentAsync();
    Assert.That(text, Does.Contain("Example"));
}

Runner: dotnet test

There is no Java CSTestingRunner. Build and run tests with the .NET SDK:

cd C:\CSTesting-DotNet
dotnet build
dotnet test

Tag filter (see README.md):

dotnet test --filter "TestCategory=smoke"

Full example (matches repo sample)

using System.Threading.Tasks;
using CSTesting;
using CSTesting.NUnit;
using NUnit.Framework;
using static CSTesting.CSTesting;

namespace MyTests;

[TestFixture]
public class SampleTests : CSTestingNUnitBrowserFixtureBase
{
    [SetUp]
    public async Task SetUp()
    {
        if (Browser == null)
            Browser = await CreateBrowserAsync(new CSTestingOptions { Headless = true });
    }

    [Test]
    [CSTestingTag("smoke")]
    public async Task ExampleDotCom()
    {
        await Browser!.GotoAsync("https://example.com");
        var text = await Browser.Locator("h1").GetTextContentAsync();
        Assert.That(text, Does.Contain("Example Domain"));
    }
}

Run: dotnet test from the test project directory.

Without CSTestingNUnitBrowserFixtureBase

You can inherit only CSTestingTestBase and call await Browser!.CloseAsync() in your own [TearDown], or manage ICSTestingBrowser in a local variable with await using / try/finally.

Summary

TopicCSTesting .NET
Test method[Test] async Task
Setup[SetUp] → create browser, assign Browser
TeardownBase fixture closes browser; or your own [TearDown]
Tags[CSTestingTag("name")] or [Category("name")]
AssertionsNUnit Assert.That; not browser.assertThat
CLIdotnet test