DrillSergeant.Xunit2 0.3.0-beta

This is a prerelease version of DrillSergeant.Xunit2.
There is a newer version of this package available.
See the version list below for details.
dotnet add package DrillSergeant.Xunit2 --version 0.3.0-beta                
NuGet\Install-Package DrillSergeant.Xunit2 -Version 0.3.0-beta                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DrillSergeant.Xunit2" Version="0.3.0-beta" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add DrillSergeant.Xunit2 --version 0.3.0-beta                
#r "nuget: DrillSergeant.Xunit2, 0.3.0-beta"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install DrillSergeant.Xunit2 as a Cake Addin
#addin nuget:?package=DrillSergeant.Xunit2&version=0.3.0-beta&prerelease

// Install DrillSergeant.Xunit2 as a Cake Tool
#tool nuget:?package=DrillSergeant.Xunit2&version=0.3.0-beta&prerelease                

DrillSergeant

.net behavior driven testing written by developers, for developers.

Build Nuget codecov CodeQL

Introduction

DrillSergeant is a behavior testing library that empowers developers to apply BDD practices with minimal amount of friction. Simply import the package and write your behaviors in familiar C# syntax. Unlike other behavior testing frameworks which rely on external feature files to write scenarios, DrillSergeant lets you write behavior tests 100% in C# code.

Getting Started

For a complete example of a feature, see the following example. For something more complex, see the DemoStore repo.

A Basic Calculator Service

Lets say we have a Calculator service. For this example we'll define it as a simple class.

public class Calculator
{
    public int Add(int a, int b) => a + b;
    public int Sub(int a, int b) => a - b;
}

We can write a behavior test like so:

public class CalculatorTests
{
    private readonly Calculator _calculator = new();

    [Behavior]
    [InlineData(1,2,3)] // [TestCase] for NUnit or [DataRow] for MSTest.
    [InlineData(2,3,5)]
    public void TestAdditionBehavior(int a, int b, int expected)
    {
        var input = new
        {
            A = a,
            B = b,
            Expected = expected
        };

        BehaviorBuilder.New(input)
            .Given(SetFirstNumber)
            .Given(SetSecondNumber)
            .When(AddNumbers)
            .Then(CheckResult);
    }

    [Behavior]
    [InlineData(3,2,1)]
    [InlineData(5,2,3)]
    public void TestSubtractionBehavior(int a, int b, int expected)
    {
        var input = new
        {
            A = a,
            B = b,
            Expected = expected
        };

        BehaviorBuilder.New(input)
            .Given(SetFirstNumber)
            .Given(SetSecondNumber)
            .When(SubtractNumbers)
            .Then(CheckResult);
    }

    // Given Steps.
    private void SetFirstNumber(dynamic context, dynamic input) => context.A = input.A;
    private void SetSecondNumber(dynamic context, dynamic input) => context.B = input.B;

    // When Steps.
    private void AddNumbers(dynamic context) => context.Result = _calculator.Add(context.A, context.B);
    private void SubtractNumbers(dynamic context) => context.Result = _calculator.Sub(context.A, context.B);

    // Then Steps.
    private void CheckResult(dynamic context, dynamic input) => Assert.Equal(input.Expected, context.Result);
}

Behaviors are written in same fashion as a normal unit test. The only difference is that it is marked using the [Behavior] attribute.

Why Write Tests This Way?

Unlike in normal unit tests, which are intended to test the correctness of individual methods, behaviors tests validate whether one or more components actually behave in the way expected when given "normal" inputs. Because of this, behaviors are composed of a series of pluggable steps that can be re-used in different scenarios. See the Cucumber documentation for an introduction into behavior testing.

Why Not Use A 3rd Party Acceptance Testing Tool (e.g. SpecFlow, Fitnesse, Guage)?

DrillSergeant was borne out of frustration of using 3rd party testing tools. While tools such as SpecFlow and Guage have gotten easier to use over time, they require installing 3rd party plugins/runners in the developer environment. Additionally they require separate files for authoring the tests themselves (.feature for Specflow, '.wiki' for FitNesse, and .md for Gauge). This relies on a mixture of code generation and reflection magic in order to bind the test specifications with the code that actually runs them, which adds a layer of complexity.

DrillSergeant takes a different approach to this problem. Rather than rely on DSLs and complex translation layers, it engrafts additional capabilities to the xunit framework to make it easy to write behavior-driven with familiar C# syntax. No new DSLs to learn, no build task fussiness, no reflection shenanigans. Just a simple API written entirely in C# code that can be tested/debugged the exact same way as all of your other unit tests.

For a longer-winded explanation, see the following blog post.

Support

Framework Support Major Version Notes
Xunit Yes 2 Full support
NUnit Yes 3 Mostly supported
MSTest Yes 2 Experimental support

Originally DrillSergeant was built around xunit and has been well tested with it. As of version 0.2.0 support has been added for NUnit and MSTest.

The NUnit integration is likely to be fairly stable since the framework was designed with extensibility support in mind. This made adding hooks for DrillSergeant fairly trivial.

The MSTest integration on the other hand should be considered experimental. This is because that framework has very limited support for extensibility and needed several somewhat invasive hacks to get working. If anyone has experience with MSTest and would like to help with this please let us know!

Installation

DrillSergeant is a regular library and can be installed via package manager with either the Install-Package or dotnet add package commands. Note that because DrillSergeant is still in beta that you will need check the 'Include Prelease' checkbox to find it in nuget manager.

Framework Package Example
Xunit DrillSergeant.Xunit2 dotnet add package DrillSergeant.Xunit2 --version 0.2.0-beta
NUnit DrillSergeant.NUnit3 dotnet add package DrillSergeant.NUnit3 --version 0.2.0-beta
MSTest DrillSergeant.MSTest dotnet add package DrillSergeant.MSTest --version 0.2.0-beta

More Information

For more information, please see the wikis.
For an introduction, please see this Medium article.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.2.2 56 4/21/2024
1.2.1 44 4/21/2024
1.2.0 59 2/20/2024
1.2.0-alpha.40 81 1/20/2024
1.2.0-alpha.39 53 1/20/2024
1.2.0-alpha.38 51 1/20/2024
1.2.0-alpha.37 54 1/20/2024
1.2.0-alpha.35 136 11/19/2023
1.2.0-alpha.34 60 11/19/2023
1.2.0-alpha.33 61 11/13/2023
1.1.8 53 2/20/2024
1.1.2 80 1/20/2024
1.1.1 194 11/12/2023
1.1.0-alpha.42 60 11/12/2023
1.1.0-alpha.41 61 11/12/2023
1.1.0-alpha.39 59 11/12/2023
1.1.0-alpha.38 63 11/12/2023
1.1.0-alpha.37 61 11/12/2023
1.1.0-alpha.35 60 11/12/2023
1.0.3 137 10/21/2023
1.0.1 119 10/12/2023
1.0.0-beta.53 72 9/30/2023
1.0.0-beta.52 68 9/29/2023
0.6.2 133 8/20/2023
0.6.1-beta 96 8/20/2023
0.6.0-beta 94 8/20/2023
0.5.0 132 7/20/2023
0.4.0 140 7/16/2023
0.3.0-beta 120 7/12/2023
0.2.0-beta 115 7/9/2023