Skip to content

tschroedter/Selkie.AutoMocking

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

47 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Selkie.AutoMocking

The Selkie.AutoMocking project is an extension for MSTest2 which provides a SUT Factory. It tries to replicate the functionality of the package AutoFixture.AutoNSubstitute and make it available for MSTest2.

Goal: The goal is to make writing unit tests easier and more refactoring-safe.
How is it done? The SUT and all the required dependencies are automatically provided to the test method.
How do I use it? Like a normal MSTest2 Data Driven Test Method.

[AutoDataTestMethod]
public void Add_ForNumbers_Adds(Calculator    sut,
                                [Freeze] IAdd add)
{
    add.Execute(1, 2)
       .Returns(3);

    sut.Add(1, 2)
       .Should()
       .Be(3);
}

AutoDataTestMethod? The attribute tells MSTest to use the Selkie.AutoMocking extension of the DataTestMethod.
Freeze? Freezing a parameter makes sure that the SUT uses the same instance ass the frozen parameter (see AutoFixture Freeze).

Example

Calculator

Let do a very simple Calculator which will show us how to use the Selkie.AutoMocking package.

The Calculator will only...

  • work for integers and
  • adds two integers together.

The complete source code can be found here: Example

The Calculator Class

The Calculator class depends on the IAdd and ISubtract interface which is injected in the constructor.

public class Calculator : ICalculator
{
    private readonly IAdd      _add;
    private readonly ISubtract _subtract;

    public Calculator([NotNull] IAdd      add,
                      [NotNull] ISubtract subtract)
    {
        Guard.ArgumentNotNull(add,
                              nameof(add));
        Guard.ArgumentNotNull(subtract,
                              nameof(subtract));

        _add      = add;
        _subtract = subtract;
    }
    ...
}

The Add Class

The job of the Add class is just to add 2 integers together.

public class Add : IAdd
{
    public int Execute(int a, int b)
    {
        return a + b;
    }
}

Unit testing the Calculator's Constructor

All my constructors in my projects make sure that the injected arguments are not null. This mean that I have to delay the creation of the SUT in my tests using Lazy and being able to set arguments to null. This can be done by using the [BeNull] attribute.

[AutoDataTestMethod]
public void Create_ForAddIsNull_Throws(Lazy<Calculator> sut,
                                       [BeNull] IAdd    add)
{
    Action action = () =>
                    {
                        // ReSharper disable once UnusedVariable
                        var actual = sut.Value;
                    };

    action.Should()
          .Throw<ArgumentNullException>()
          .WithParameter("add");
}

Unit testing the Calculator's Add method

The example below shows how to test the Add method using the AutoDataTestMethod of the Selkie.AutoMocking package.

using Calculator.Interfaces;
using FluentAssertions;
using NSubstitute;
using Selkie.AutoMocking;

namespace Calculator.Tests
{
    [AutoDataTestClass]
    public class CalculatorTests
    {
        [AutoDataTestMethod]
        public void Add_ForNumbers_Adds(Calculator    sut,
                                        [Freeze] IAdd add)
        {
            add.Execute(1, 2)
               .Returns(3);

            sut.Add(1, 2)
               .Should()
               .Be(3);
        }
    }
}

Note: There isn't a method to initialize the test nor a CreateSut() method!

Adding subtraction to the Calculator

Now we add the subtraction functionality to the Calculator class by adding a dependency in the constructor.

public class Calculator : ICalculator
{
    private readonly IAdd      _add;
    private readonly ISubtract _subtract;

    public Calculator([NotNull] IAdd      add,
                      [NotNull] ISubtract subtract)
    {
        _add      = add;
        _subtract = subtract;
    }

    public int Add(int a, int b)
    {
        return _add.Execute(a, b);
    }

    public int Subtract(int a, int b)
    {
        return _subtract.Execute(a, b);
    }
}

How is the unit test class affected?

No existing code needs to be modified, only the new test for the subtraction needs to be added!

[AutoDataTestClass]
public class CalculatorTests
{
    [AutoDataTestMethod]
    public void Add_ForNumbers_Adds(Calculator    sut,
                                    [Freeze] IAdd add)
    {
        add.Execute(1, 2)
           .Returns(3);

        sut.Add(1, 2)
           .Should()
           .Be(3);
    }

    [AutoDataTestMethod]
    public void Subtract_ForNumbers_Subtracts(Calculator         sut,
                                              [Freeze] ISubtract subtract)
    {
        subtract?.Execute(1, 2)
                 .Returns(-1);

        sut.Subtract(1, 2)
           .Should()
           .Be(-1);
    }
}

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages