ToolBX.Eloquentest 2.1.2-beta4

This is a prerelease version of ToolBX.Eloquentest.
There is a newer version of this package available.
See the version list below for details.
dotnet add package ToolBX.Eloquentest --version 2.1.2-beta4                
NuGet\Install-Package ToolBX.Eloquentest -Version 2.1.2-beta4                
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="ToolBX.Eloquentest" Version="2.1.2-beta4" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add ToolBX.Eloquentest --version 2.1.2-beta4                
#r "nuget: ToolBX.Eloquentest, 2.1.2-beta4"                
#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 ToolBX.Eloquentest as a Cake Addin
#addin nuget:?package=ToolBX.Eloquentest&version=2.1.2-beta4&prerelease

// Install ToolBX.Eloquentest as a Cake Tool
#tool nuget:?package=ToolBX.Eloquentest&version=2.1.2-beta4&prerelease                

Eloquentest

Eloquentest

A simple to use .NET unit testing framework built on top of MSTest and Moq. It also includes built-in support for services that are injected using [AutoInject].

Getting started

Here is the dumbest service you can imagine.

    public class DumbestServiceYouCanImagine
    {
        public string Format(int number)
        {
            return number == 0 ? "It's zero" : "It's not zero";
        }
    }

Here is the dumbest unit test for the dumbest service you can imagine.

    [TestClass]
    public class DumbestServiceYouCanImagineTester : Tester<DumbestServiceYouCanImagine>
    {
        [TestMethod]
        public void WhenNumberIsZero_ReturnItsZero()
        {
            //Act
            var result = Instance.Format(0);

            //Assert
            Assert.AreEqual("It's zero", result);
        }
    }

That's all well and good but what if your dumb service had dependencies to other services though?

public interface ISomeOtherService
{
    public string UserId { get; }
    public IReadOnlyList<int> Roles { get; }
}
public class DumbestServiceYouCanImagine
{
    private readonly ISomeOtherService _someOtherService;

    public DumbestServiceYouCanImagine(ISomeOtherService someOtherService)
    {
        _someOtherService = someOtherService;
    }

    public string DoSomeOtherStuff()
    {
        return _someOtherService.Roles.Contains(8) ? 
            $"User {_someOtherService.UserId} is authorized to do dumb stuff." : 
            $"User {_someOtherService.UserId} is strictly forbidden from doing dumb stuff!";
    }
}
[TestClass]
public class DumbestServiceYouCanImagineTester : Tester<DumbestServiceYouCanImagine>
{
    [TestMethod]
    public void WhenContainsRoleNumberEight_SayThatUserIsAuthorized()
    {
        //Arrange
        var userId = Fixture.Create<string>();
        GetMock<ISomeOtherService>().Setup(x => x.UserId).Returns(userId);
        
        GetMock<ISomeOtherService>().Setup(x => x.Roles).Returns(new List<int> { 8 });

        //Act
        var result = Instance.DoSomeOtherStuff();

        //Assert
        Assert.AreEqual($"User {userId} is authorized to do dumb stuff.", result);
    }

    [TestMethod]
    public void WhenDoesNotContainRoleNumberEight_SayThatUserIsUnauthorized()
    {
        //Arrange
        var userId = Fixture.Create<string>();
        GetMock<ISomeOtherService>().Setup(x => x.UserId).Returns(userId);

        GetMock<ISomeOtherService>().Setup(x => x.Roles).Returns(new List<int>());

        //Act
        var result = Instance.DoSomeOtherStuff();

        //Assert
        Assert.AreEqual($"User {userId} is strictly forbidden from doing dumb stuff!", result);
    }
}

[AutoCustomization]

//This Customization will be applied project-wide so you don't have to remember to add them yourself each time in TestInitialize
[AutoCustomization]
public class SomeCustomization : ICustomization
{
    ...
}

//Also works with ISpecimenBuilder
[AutoCustomization]
public class SomeSpecimenBuilder : ISpecimenBuilder
{
    ...
}

Testing collections

Ever wanted to test whichever item from a collection?

[TestMethod]
public void WhenYouWantWhichever_GetWhichever()
{
    //Arrange
    var list = Fixture.CreateMany<string>().ToList();

    var something = Fixture.Create<Something>();
    GetMock<ISomeShadyService>().Setup(x => x.GetSomething(list.GetRandom())).Returns(something);

    //Act
    var result = Instance.DoSomething(list);

    //Assert
    result.Should.BeEquivalentTo(something);
}

You can also do the same thing but with the index only if that's what floats your boat.

var index = list.GetRandomIndex();

Using the generic tester with custom constructor parameters

It�s all well and good but what if you want to use the generic Tester class while providing your own parameters to the tested class� constructor instead of the automatically generated mocks and fixtures?

You can do that with the ConstructWith() method.

[AutoInject]
public class GameObjectFactory : IGameObjectFactory
{
    private readonly IServiceProvider _serviceProvider;

    public GameObjectFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public IGameObject Create(GameObjectConfiguration configuration) => new GameObject(_serviceProvider, configuration);
}

public record GameObjectConfiguration(string Name, Vector2<float> InitialPosition, Direction InitialDirection);

//The service provider is passed by the GameObjectFactory and is always the same reference
//Configuration is unique to every instance so we need to be able to override it if we want to test that things are correctly initialized
public GameObject(IServiceProvider serviceProvider, GameObjectConfiguration configuration)
{
    _game = serviceProvider.GetRequiredService<IGame>();
    Name = configuration.Name;
    Position = configuration.InitialPosition;
    Direction = configuration.InitialDirection;
}

[TestClass]
public class GameObjectTester 
{
    [TestClass]
    public class Move : Tester<GameObject>
    {
        [TestMethod]
        public void Always_ChangePosition()
        {
            //Arrange
            var configuration = Fixture.Create<GameObjectConfiguration>();

            //It is important to call ConstructWith before accessing the Instance property!
            ConstructWith(configuration);

            //Act
            Instance.Move(new Vector2<float>(1, 0));

            //Assert
            Instance.Position.Should().Be(configuration.InitialPosition + new Vector2<float>(1, 0));
        }
    }
}

AutoFillTester

Works just like Tester<T> except that it automatically fills your Instance's public set and init with values. Works in a lot of cases but you might want to stick with Tester<T> for others.

Integration tests

The Eloquentest.Integration namespace (available on nuget.org as a separate package) provides tools to leverage MSTest to execute code without mocking all while using the Eloquentest structure and syntax you may already be familiar with.

IntegrationTester and IntegreationTester<T> replace Tester and Tester<T> and there are no mocks.

Setup

It works right out of the box if you already use AutoInject in your regular code.

Breaking changes

1.0.X → 1.1.X GetRandom and GetRandomIndex methods have been removed from Eloquentest. Please import and use ToolBX.OPEX from nuget.org instead.

2.0.X → 2.1.0 AutoFillTester<T> was addded. There have been minor changes in when things are instantiated which may affect some users in Tester and Tester<T>.

Product Compatible and additional computed target framework versions.
.NET 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.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on ToolBX.Eloquentest:

Package Downloads
ToolBX.Eloquentest.Dummies

Package Description

ToolBX.Eloquentest.AutoFixture

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
3.0.0 3,337 9/27/2024
3.0.0-beta4 300 9/22/2024
3.0.0-beta3 77 9/22/2024
3.0.0-beta2 127 9/7/2024
3.0.0-beta1 182 8/27/2024
2.2.1 3,930 1/17/2024
2.2.1-beta.1 67 1/14/2024
2.2.0 249 1/11/2024
2.2.0-beta97 167 1/7/2024
2.2.0-beta96 103 1/4/2024
2.2.0-beta94 122 12/29/2023
2.2.0-beta93 136 12/29/2023
2.2.0-beta92 102 12/29/2023
2.2.0-beta91 120 12/29/2023
2.2.0-beta9 148 12/14/2023
2.2.0-beta8 107 12/13/2023
2.2.0-beta7 140 11/24/2023
2.2.0-beta6 106 11/22/2023
2.2.0-beta5 108 11/22/2023
2.2.0-beta4 117 11/17/2023
2.2.0-beta3 100 11/17/2023
2.2.0-beta2 94 11/17/2023
2.2.0-beta11 133 12/27/2023
2.2.0-beta10 124 12/14/2023
2.2.0-beta1 108 11/17/2023
2.2.0-beta.12 85 12/28/2023
2.2.0-alpha.1 80 12/28/2023
2.1.4 2,761 11/22/2023
2.1.4-beta4 106 11/22/2023
2.1.4-beta3 115 11/17/2023
2.1.4-beta2 122 11/2/2023
2.1.4-beta1 105 10/28/2023
2.1.3 2,582 10/17/2023
2.1.3-beta1 103 10/17/2023
2.1.2 559 10/4/2023
2.1.2-beta7 145 10/3/2023
2.1.2-beta6 717 8/29/2023
2.1.2-beta5 109 8/28/2023
2.1.2-beta4 109 8/25/2023
2.1.2-beta3 119 8/24/2023
2.1.2-beta2 1,865 6/23/2023
2.1.2-beta1 134 6/22/2023
2.1.1 331 6/19/2023
2.1.0 258 6/13/2023
2.1.0-beta3 157 6/13/2023
2.1.0-beta2 134 6/12/2023
2.1.0-beta1 145 6/10/2023
2.0.2 978 4/25/2023
2.0.1 206 4/23/2023
2.0.0 410 11/9/2022
2.0.0-beta2 165 9/28/2022
2.0.0-beta1 161 9/20/2022
1.1.2 425 9/28/2022
1.1.1 432 9/20/2022
1.1.1-beta3 173 8/10/2022
1.1.1-beta2 149 8/10/2022
1.1.1-beta1 147 8/10/2022
1.1.0 407 8/10/2022
1.0.7 407 5/27/2022
1.0.6 419 5/16/2022
1.0.5 457 3/15/2022
1.0.5-beta 167 3/15/2022
1.0.4 470 2/5/2022
1.0.3 436 2/4/2022
1.0.2 429 1/14/2022
1.0.1 265 12/22/2021
1.0.0 302 12/15/2021