Home

Awesome

BDTest

A testing and reporting framework for .NET

nuget Codacy Badge CodeFactor Nuget

Support

If you like using BDTest, consider buying me a coffee.

<a href="https://www.buymeacoffee.com/tomhurst" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy Me A Coffee" style="height: auto !important;width: auto !important;" ></a>

Wiki

Please view the wiki to see how to use BDTest and how to get setup: https://github.com/thomhurst/BDTest/wiki

What is it?

BDTest is a testing and reporting framework focusing on 'Behaviour Driven Testing' ideologies. It's a way to structure and run your tests so that:

BDTest can be used standalone, or alongside an existing test running framework. For best results, I recommend NUnit, and installing the BDTest.NUnit package alongside the core BDTest package.

Why?

I was originally inspired to build BDTest due to SpecFlow. My team at work used SpecFlow (as does much of the .NET based industry) for their tests when I joined, and upon using it, realised I really didn't enjoy using it and found it to be difficult to work with, finnicky and long-winded. It turned out, my team also really disliked it, so I thought I'd change things.

Think of BDTest as a pure code-based alternative to SpecFlow.

What's the benefit over SpecFlow?

But non-technical team members can write tests using SpecFlow

I need reports that translates to business acceptance criteria

Where can I use it?

BDTest is written in .NET Standard, so you can use it in either .NET Framework or .NET Core

How do I get started?

View the wiki to see how to use BDTest and how to get setup: https://github.com/thomhurst/BDTest/wiki

Example Test

namespace BDTest.Example
{
    [Story(AsA = "BDTest author",
        IWant = "to show an example of how to use the framework",
        SoThat = "people can get set up easier")]
    public class ExampleTest : NUnitBDTestContext<MyTestContext>
    {
        // Context property is magically available, created by the `NUnitBDTestContext` base class. It's unique for each NUnit test!
        private AccountSteps AccountSteps => new AccountSteps(Context);
        private HttpAssertionsSteps HttpAssertions => new HttpAssertionsSteps(Context);
        
        [Test]
        [ScenarioText("Searching for a non-existing account number returns Not Found")]
        public async Task FindNonExistingAccountReturnsNotFound()
        {
            await When(() => AccountSteps.FindAccount(12345))
                .Then(() => HttpAssertions.TheHttpStatusCodeIs(HttpStatusCode.NotFound))
                .BDTestAsync();
        }
        
        [Test]
        [BugInformation("123456")]
        [ScenarioText("Can successfully create a new account")]
        public async Task CreateNewAccountSuccessfully()
        {
            await When(() => AccountSteps.CreateAnAccount())
                .Then(() => HttpAssertions.TheHttpStatusCodeIs(HttpStatusCode.OK))
                .BDTestAsync();
        }
    }
    
    public class AccountSteps
    {
        private MyTestContext _context;
        
        public class AccountSteps(MyTestContext context)
        {
            _context = context;
        }
        
        [StepText("I create an account")
        public async Task CreateAnAccount()
        {
            // ... Some code to create an account!
            // You can use all the information stored in your test context object that was passed into the constructor!
            // And store stuff for later use - Such as assertions!
            // e.g. 
            // var request = new HttpRequestMessage { Method = POST, Body = SomeBody, Uri = SomeUri };
            // _context.HttpResponse = await HttpHelper.SendAsync(request);
        }
        
        [StepText("I search for the account with the customer ID '{0}'")
        public async Task FindAccount(int customerId)
        {
            // ... Some code to find an account!
            // e.g. 
            // var request = new HttpRequestMessage { Method = GET, Uri = $"{SomeUri}/{customerId}" };
            // _context.HttpResponse = await HttpHelper.SendAsync(request);
        }
    }
    
    public class HttpAssertionsSteps
    {
        private MyTestContext _context;
        
        public class HttpAssertionsSteps(MyTestContext context)
        {
            _context = context;
        }
        
        [StepText("the HTTP status code is {0}")
        public async Task TheHttpStatusCodeIs(HttpStatusCode code)
        {
            // ... Some code to assert - Read data previously stored in your context object!
            // e.g.
            // Assert.That(_context.HttpResponse.StatusCode, Is.EqualTo(code));
        }
    }
}

Report Server Example Image

Report Server Example Image