FastMoq 2.25.0

dotnet add package FastMoq --version 2.25.0
NuGet\Install-Package FastMoq -Version 2.25.0
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="FastMoq" Version="2.25.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add FastMoq --version 2.25.0
#r "nuget: FastMoq, 2.25.0"
#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 FastMoq as a Cake Addin
#addin nuget:?package=FastMoq&version=2.25.0

// Install FastMoq as a Cake Tool
#tool nuget:?package=FastMoq&version=2.25.0

FastMoq

Easy and fast extension of the Moq mocking framework for mocking and auto injection of classes when testing.

API Documentation

FastMoq API Documentation

Features

  • NOW BLAZOR SUPPORT in FastMoq and FastMoq.Web.
  • Test without declaring Mocks (unless needed).
  • Creates objects with chain of automatic injections in objects and their dependencies.
  • Creates Mocks and Objects with properties populated.
  • Automatically injects and creates components or services.
  • Injection: Automatically determines what interfaces need to be injected into the constructor and creates mocks if they do not exist.
    • Generate Mock using specific data.
    • Best guess picks the multiple parameter constructor over the default constructor.
    • Specific mapping allows the tester to create an instance using a specific constructor and specific data.
    • Supports Inject Attributes and multiple constructors.
  • Use Mocks without managing fields and properties. Mocks are managed by the Mocker framework. No need to keep track of Mocks. Just use them!
  • Create instances of Mocks with non public constructors.
  • HttpClient and IFileSystem test helpers
  • DbContext support - SqlLite and mockable objects.
  • Supports Null method parameter testing.

Packages

  • FastMoq - Combines FastMoq.Core and FastMoq.Web.
  • FastMoq.Core - Original FastMoq testing Mocker.
  • FastMoq.Web - New Blazor and Web support.

Targets

  • .NET 8
  • .NET 7
  • .NET 6

Most used classes in the FastMoq namespace

public class Mocker {} // Primary class for auto mock and injection. This can be used standalone from MockerTestBase using Mocks property on the base class.
public abstract class MockerTestBase<TComponent> where TComponent : class {} // Assists in the creation of objects and provides direct access to Mocker.

Most used classes in the FastMoq.Web.Blazor namespace

public abstract class MockerBlazorTestBase<T> : TestContext, IMockerBlazorTestHelpers<T> where T : ComponentBase // Assists in the creation of Blazor components and provides direct access to Mocker.

Examples

Basic example of the base class creating the Car class and auto mocking ICarService

public class CarTest : MockerTestBase<Car> {
     [Fact]
     public void TestCar() {
         Component.Color.Should().Be(Color.Green);
         Component.CarService.Should().NotBeNull();
     }
}

public class Car {
     public Color Color { get; set; } = Color.Green;
     public ICarService CarService { get; }
     public Car(ICarService carService) => CarService = carService;
}

public interface ICarService
{
     Color Color { get; set; }
     ICarService CarService { get; }
     bool StartCar();
}

Example of how to set up for mocks that require specific functionality

public class CarTest : MockerTestBase<Car> {
     public CarTest() : base(mocks => {
             mocks.Initialize<ICarService>(mock => mock.Setup(x => x.StartCar).Returns(true));
     }
}

Auto Injection

Auto injection allows creation of components with parameterized interfaces. If an override for creating the component is not specified, the component will be created will the default Mock Objects.

Auto Injection with instance parameters

Additionally, the creation can be overwritten and provided with instances of the parameters. CreateInstance will automatically match the correct constructor to the parameters given to CreateInstance.

Mocks.CreateInstance(new MockFileSystem()); // CreateInstance matches the parameters and types with the Component constructor.
Interface Type Map

When multiple classes derive from the same interface, the Interface Type Map can map with class to use for the given injected interface. The map can also enable mock substitution.

Example of two classes inheriting the same interface
public class TestClassDouble1 : ITestClassDouble {}
public class TestClassDouble2 : ITestClassDouble {}
Mapping

This code maps ITestClassDouble to TestClassDouble1 when testing a component with ITestClassDouble.

Mocker.AddType<ITestClassDouble, TestClassDouble1>();

The map also accepts parameters to tell it how to create the instance.

Mocks.AddType<ITestClassDouble, TestClassDouble1>(() => new TestClassDouble());

DbContext Mocking

Create Your DbContext. The DbContext can either have virtual DbSet(s) or an interface. In this example, we use virtual DbSets.

Suppose you have an ApplicationDbContext with a virtual DbSet<Blog>:

public class ApplicationDbContext : DbContext
{
    public virtual DbSet<Blog> Blogs { get; set; }
    // ...other DbSet properties

    // This can be public, but we make it internal to hide it for testing only.
    // This is only required if the public constructor does things that we don't want to do.
    internal ApplicationDbContext()
    {
        // In order for an internal to work, you may need to add InternalsVisibleTo attribute in the AssemblyInfo or project to allow the mocker to see the internals.
        // [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
    }

    // Public constructor used by application.
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) => Database.EnsureCreated();

    // ... Initialize and setup
}

Suppose you want to test a repository class that uses the ApplicationDbContext:

public class BlogRepo(ApplicationDbContext dbContext)
{
    public Blog? GetBlogById(int id) => dbContext.Blogs.AsEnumerable().FirstOrDefault(x => x.Id == id);
}
Sample Unit Test Using DbContext in MockerTestBase

In your unit test, you want to override the SetupMocksAction to create a mock DbContext using Mocker. Here’s an example using xUnit:

public class BlogRepoTests : MockerTestBase<BlogRepo>
{
    // This runs actions before BlogRepo is created.
    // This cannot be done in the constructor because the component is created in the base class.
    // An alternative way is to pass the code to the base constructor.
    protected override Action<Mocker> SetupMocksAction => mocker =>
    {
        var dbContextMock = mocker.GetMockDbContext<ApplicationDbContext>(); // Create DbContextMock
        mocker.AddType(_ => dbContextMock.Object); // Add DbContext to the Type Map.
        // In this example, we don't use a IDbContextFactory, but if we did, it would do this instead of AddType:
        // mocker.GetMock<IDbContextFactory<ApplicationDbContext>>().Setup(x => x.CreateDbContext()).Returns(dbContextMock.Object);
    };

    [Fact]
    public void GetBlog_ShouldReturnBlog_WhenPassedId()
    {
        // Arrange
        const int ID = 1234;
        var blogsTestData = new List<Blog> { new() { Id = ID } };

        // Create a mock DbContext
        var dbContext = Mocks.GetRequiredObject<ApplicationDbContext>();
        dbContext.Blogs.AddRange(blogsTestData); // Can also be dbContext.Set<Blog>().AddRange(blogsTestData)

        // Act
        var result = Component.GetBlogById(ID);

        // Assert
        Assert.NotNull(result);
        Assert.True(result.Id.Equals(ID));
    }
}

Run Your Tests: Execute your unit tests, and the mock DbContext will behave like a real DbContext, allowing you to test your BlogRepo logic without hitting the actual database.

Sample Unit Test Using DbContext Directly In Test Methods

In your unit test, you want to create a mock DbContext using Mocker. This can be done directly in the test if the context is either only needed for the method or the component is created manually. Here’s an example using xUnit:

public class BtnValidatorTests
{
    [Fact]
    public void BtnValidatorIsValid_ShouldReturnTrue()
    {
        // Arrange
        var id = 1234;
        var blogsTestData = new List<Blog> { new Blog { Id = id } };

        // Create a mock DbContext
        var mocker = new Mocker(); // Create a new mocker only if not already using MockerTestBase; otherwise use Mocks included in the base class.

        var dbContextMock = mocker.GetMockDbContext<ApplicationDbContext>();
        var dbContext = dbContextMock.Object;
        dbContext.Blogs.Add(blogsTestData); // Can also be dbContext.Set<Blog>().Add(blogsTestData)

        var validator = new BtnValidator(dbContext);

        // Act
        var result = validator.IsValid(id);

        // Assert
        Assert.True(result);
    }
}

Run Your Tests: Execute your unit tests, and the mock DbContext will behave like a real DbContext, allowing you to test your BtnValidator logic without hitting the actual database.

Null / Parameter checking

Testing constructor parameters is very easy with TestAllConstructorParameters and TestConstructorParameters.

TestConstructorParameters - Test the constructor that MockerTestBase used to create the Component for the test. TestAllConstructorParameters - Test all constructors in the component, regardless if the constructor was used to create the component for the test.

Example: Check values for null
    // Check values for null
    [Fact]
    public void Service_NullArgChecks() => TestConstructorParameters((action, constructorName, parameterName) =>
    {
        output?.WriteLine($"Testing {constructorName}\n - {parameterName}");
        
        action
            .Should()
            .Throw<ArgumentNullException>()
            .WithMessage($"*{parameterName}*");
    });

Example: Check values for specific criteria
        
    // Check values for specific criteria.
    [Fact]
    public void Service_NullArgChecks() => TestConstructorParameters((action, constructorName, parameterName) =>
        {
            output?.WriteLine($"Testing {constructorName}\n - {parameterName}");
        
            action
                .Should()
                .Throw<ArgumentNullException>()
                .WithMessage($"*{parameterName}*");
        },
        info =>
        {
            return info switch
            {
                { ParameterType: { Name: "string" }} => string.Empty,
                { ParameterType: { Name: "int" }} => -1,
                _ => default,
            };
        },
        info =>
        {
            return info switch
            {
                { ParameterType: { Name: "string" }} => "Valid Value",
                { ParameterType: { Name: "int" }} => 22,
                _ => Mocks.GetObject(info.ParameterType),
            };
        }
    );
Example: Test constructors for null with output
    // Test constructors for null, using built-in extension and log the output.
    [Fact]
    public void TestAllConstructors_WithExtension()
    {
        var messages = new List<string>();
        TestAllConstructorParameters((action, constructor, parameter) => action.EnsureNullCheckThrown(parameter, constructor, messages.Add));

        messages.Should().Contain(new List<string>()
            {
                "Testing .ctor(IFileSystem fileSystem, String field)\n - fileSystem",
                "Passed fileSystem",
                "Testing .ctor(IFileSystem fileSystem, String field)\n - field",
                "Passed field",
            }
        );
    }

Troubleshooting

System.MethodAccessException

If the test returns:

  • System.MethodAccessException: Attempt by method 'Castle.Proxies.ApplicationDbContextProxy..ctor(Castle.DynamicProxy.IInterceptor[])' to access method

Add the following InternalsVisibleTo line to the AssemblyInfo file. [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

Additional Documentation

FastMoq API Documentation

Full Change Log

Full Change Log

Breaking Change

  • 2.25.Latest ⇒ Some methods moved to extensions that are no longer in the MockerTestBase or Mocker. Removed extra CreateInstance<T> methods.
  • 2.23.200 ⇒ Support .NET 8
  • 2.23.x ⇒ Removed support for .NET Core 5.
  • 2.22.1215 ⇒ Removed support for .NET Core 3.1 in FastMoq.Core. Deprecated .NET Core 5 and moved package supporting .NET Core 5.0 from FastMoq to FastMoq.Core.
  • 1.22.810 ⇒ Removed setters on the MockerTestBase virtual methods: SetupMocksAction, CreateComponentAction, CreatedComponentAction
  • 1.22.810 ⇒ Update Package Dependencies
  • 1.22.728 ⇒ Initialize method will reset the mock, if it already exists. This is overridable by settings the reset parameter to false.
  • 1.22.604 ⇒ Renamed Mocks to Mocker, Renamed TestBase to MockerTestBase.

License - MIT

http://help.fastmoq.com

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 is compatible.  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
2.25.0 67 4/10/2024
2.24.300 276 2/1/2024
2.23.201 502 12/13/2023
2.23.200 413 12/2/2023
2.23.124 453 11/7/2023
2.23.123 434 11/3/2023
2.23.122 483 10/11/2023
2.23.120 539 8/31/2023
2.23.118 681 5/24/2023
2.23.117 596 5/4/2023
2.23.116 695 3/31/2023
2.23.115 768 1/14/2023
2.23.113.2138 741 1/13/2023
2.22.1215.1748 800 12/15/2022
1.22.1128.2310 830 11/28/2022
1.22.1117.1322 824 11/17/2022
1.22.1113.29 818 11/13/2022
1.22.1111.1837 824 11/11/2022
1.22.831.1343 890 8/31/2022
1.22.810.1759 894 8/10/2022
1.22.809.1253 904 8/9/2022
1.22.805.1334 932 8/5/2022
1.22.728.1251 894 7/28/2022
1.22.727.1847 875 7/27/2022
1.22.604.1441 908 6/4/2022
1.22.531.1514 923 5/31/2022
1.22.531.1336 877 5/31/2022
1.22.529.1812 881 5/29/2022
1.0.0 396 11/3/2023