TestKase
TestKase
|Docs
Test ManagementAutomationTest Frameworks

NUnit

Set up NUnit for .NET testing and integrate test results with TestKase.

Overview

NUnit is the most popular unit testing framework for .NET applications. It provides a rich set of assertions, parameterized tests, setup/teardown lifecycle hooks, and category-based test filtering. NUnit 3 is the current major version and produces a well-defined XML output format.

To integrate NUnit results with TestKase, generate NUnit 3 XML output and report with --format nunit.

Prerequisites

  • .NET SDK 6.0+ (or .NET 8.0+ recommended)

Installation

New Project

Create a new NUnit test project using the built-in template:

dotnet new nunit -n MyProject.Tests

This scaffolds a project with all required NUnit packages pre-configured.

Existing Project

Add NUnit packages to an existing test project:

dotnet add package NUnit
dotnet add package NUnit3TestAdapter
dotnet add package Microsoft.NET.Test.Sdk

For NUnit XML output, also install the logger:

dotnet add package NunitXml.TestLogger

Project Setup

Your .csproj file should include these package references:

<!-- MyProject.Tests.csproj -->
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <IsPackable>false</IsPackable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
    <PackageReference Include="NUnit" Version="4.1.0" />
    <PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
    <PackageReference Include="NunitXml.TestLogger" Version="3.1.20" />
  </ItemGroup>

</Project>

Directory Structure

MyProject.Tests/
  MyProject.Tests.csproj
  LoginTests.cs
  DashboardTests.cs
  Helpers/
    TestData.cs

Writing Tests

Create a test file (e.g., LoginTests.cs):

// LoginTests.cs
using NUnit.Framework;

namespace MyProject.Tests
{
    [TestFixture]
    public class LoginTests
    {
        private LoginService _loginService;

        [SetUp]
        public void SetUp()
        {
            _loginService = new LoginService();
        }

        [TearDown]
        public void TearDown()
        {
            _loginService = null;
        }

        [Test]
        public void Test_48271_ValidLogin()
        {
            var result = _loginService.Login("user@example.com", "password123");
            Assert.That(result.Success, Is.True);
            Assert.That(result.Token, Is.Not.Null);
        }

        [Test]
        public void Test_48272_InvalidPassword()
        {
            var result = _loginService.Login("user@example.com", "wrong");
            Assert.That(result.Success, Is.False);
            Assert.That(result.Error, Is.EqualTo("Invalid credentials"));
        }

        [Test]
        public void Test_48273_EmptyEmailThrowsException()
        {
            Assert.That(
                () => _loginService.Login("", "password123"),
                Throws.ArgumentException.With.Message.Contains("Email is required")
            );
        }

        [TestCase("user@example.com", "password123", true)]
        [TestCase("admin@example.com", "admin456", true)]
        [TestCase("unknown@example.com", "wrong", false)]
        public void Test_48274_LoginWithMultipleUsers(string email, string password, bool expected)
        {
            var result = _loginService.Login(email, password);
            Assert.That(result.Success, Is.EqualTo(expected));
        }
    }
}

Each test embeds a 5-digit Automation ID in its method name using underscores (e.g. Test_48271_ValidLogin). The NUnit parser reads only each test case's name/fullname attribute — the [Description] attribute is emitted as a <property> child element that the reporter never reads — so the ID must live in the method name. Configure the reporter with --automation-id-format "_(\\d{5})_" to extract the ID from between the underscores. For the example above:

  • 48271 → linked to the "valid login" test case in TestKase
  • 48272 → linked to the "invalid password" test case in TestKase
  • 48273 → linked to the "empty email" test case in TestKase
  • 48274 → linked to the "multiple users" test case in TestKase

The NUnit 3 results file exposes each test as <test-case name="..." fullname="...">, and the reporter matches against those attributes only. IDs placed in [Description("[48271] ...")] become a <property> child and are not read — they will never match. Put the ID in the method name and pass --automation-id-format "_(\\d{5})_".

Generate Automation IDs in TestKase first, then embed them in your test method names.

Running Tests

Run all tests:

dotnet test

Run with verbose output:

dotnet test --verbosity normal

Generating NUnit XML Output

Use the NUnit XML logger to produce NUnit 3 format output:

dotnet test --logger "nunit;LogFileName=nunit-results.xml" --results-directory test-results

This writes the results to test-results/nunit-results.xml.

You can add the logger configuration to a .runsettings file or pass it as a command-line argument. The --results-directory flag controls where the output file is written.

TestKase Integration

After generating the NUnit XML file, report results to TestKase:

npx @testkase/reporter report \
  --token $TESTKASE_PAT \
  --project-id PRJ-1 \
  --org-id 1173 \
  --cycle-id TCYCLE-5 \
  --format nunit \
  --automation-id-format "_(\\d{5})_" \
  --results-file test-results/nunit-results.xml

--cycle-id is optional. If not provided, results are reported to TCYCLE-1 — the master test cycle for the project.

Automation ID Mapping

The reporter extracts 5-digit Automation IDs from the NUnit method name using the --automation-id-format "_(\\d{5})_" pattern (the ID wrapped in underscores):

Test PatternWhere to Embed the IDExtracted ID
Standard testpublic void Test_48271_ValidLogin()48271
Parameterized with [TestCase]public void Test_48274_LoginWithMultipleUsers(...)48274
Nested namespacepublic void Test_48275_ValidateToken()48275

The parser reads the <test-case> name/fullname attribute only — the [Description] attribute is ignored. For parameterized tests, all parameter variations share the same Automation ID.

Complete Example

1. Test File

// LoginTests.cs
using NUnit.Framework;

namespace MyProject.Tests
{
    [TestFixture]
    public class LoginTests
    {
        private LoginService _loginService;

        [SetUp]
        public void SetUp()
        {
            _loginService = new LoginService();
        }

        [Test]
        public void Test_48271_ValidLogin()
        {
            var result = _loginService.Login("user@example.com", "password123");
            Assert.That(result.Success, Is.True);
        }

        [Test]
        public void Test_48272_InvalidPassword()
        {
            var result = _loginService.Login("user@example.com", "wrong");
            Assert.That(result.Success, Is.False);
        }
    }
}

2. Run Tests and Generate NUnit XML

dotnet test --logger "nunit;LogFileName=nunit-results.xml" --results-directory test-results

3. Report Results to TestKase

npx @testkase/reporter report \
  --token $TESTKASE_PAT \
  --project-id PRJ-1 \
  --org-id 1173 \
  --cycle-id TCYCLE-5 \
  --format nunit \
  --automation-id-format "_(\\d{5})_" \
  --results-file test-results/nunit-results.xml

Troubleshooting

NUnit logger not found

If you get an error like The test logger 'nunit' was not found, the NunitXml.TestLogger package is not installed. Add it to your project:

dotnet add package NunitXml.TestLogger

After installing, rebuild and run again:

dotnet build
dotnet test --logger "nunit;LogFileName=nunit-results.xml" --results-directory test-results

Test adapter not loaded

If tests are not discovered or you see No test is available, ensure the NUnit3TestAdapter package is referenced in your .csproj:

dotnet add package NUnit3TestAdapter

Also verify that Microsoft.NET.Test.Sdk is installed — this is required for the dotnet test command to discover and run NUnit tests:

dotnet add package Microsoft.NET.Test.Sdk

Wrong XML format (NUnit 2 vs NUnit 3)

The TestKase reporter expects NUnit 3 XML format. If you are using an older NUnit 2 runner or a third-party logger that produces NUnit 2 format, the reporter will fail to parse the results.

To verify you are using NUnit 3 format, check the root element of the generated XML:

  • NUnit 3: <test-run> root element
  • NUnit 2: <test-results> root element

If you see <test-results>, switch to the NunitXml.TestLogger package which produces the correct NUnit 3 format. Do not use the older NUnit.ConsoleRunner unless you confirm it outputs NUnit 3 XML.