Light.DataAccessMocks 3.0.0

dotnet add package Light.DataAccessMocks --version 3.0.0
                    
NuGet\Install-Package Light.DataAccessMocks -Version 3.0.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="Light.DataAccessMocks" Version="3.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Light.DataAccessMocks" Version="3.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Light.DataAccessMocks" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Light.DataAccessMocks --version 3.0.0
                    
#r "nuget: Light.DataAccessMocks, 3.0.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.
#addin nuget:?package=Light.DataAccessMocks&version=3.0.0
                    
Install Light.DataAccessMocks as a Cake Addin
#tool nuget:?package=Light.DataAccessMocks&version=3.0.0
                    
Install Light.DataAccessMocks as a Cake Tool

Light.DataAccessMocks

This library provides mocks for the data access abstractions of Light.SharedCore that you can use in your unit tests.

Light Logo

License NuGet

How to install

Light.DataAccessMocks is compiled against .NET Standard 2.0 and 2.1 and thus supports all major platforms like .NET and .NET Framework, Mono, Xamarin, UWP, or Unity.

Light.DataAccessMocks is available as a NuGet package and can be installed via:

  • Package Reference in csproj: <PackageReference Include="Light.DataAccessMocks" Version="3.0.0" />
  • dotnet CLI: dotnet add package Light.DataAccessMocks
  • Visual Studio Package Manager Console: Install-Package Light.DataAccessMocks

What does Light.DataAccessMocks offer you?

With Light.DataAccessMocks, you can easily create mock clients and sessions for the data access abstractions of Light.SharedCore. This library provides base classes that allow you to easily check that a session was correctly disposed, that changes were saved, or that a session was never opened.

Mocking clients

Clients or read-only sessions are those humble objects that do not explicitly interact with transactions or change tracking, typically to only read data from your source system. Calling code usually simply disposes a client when the connection to the third-party system is no longer needed. You can derive from the AsyncDisposableMock or DisposableMock to mock the IAsyncDisposable or IDisposable interfaces. The following example shows this for an asynchronous use case:

public interface IGetContactSession : IAsyncDisposable
{
    Task<Contact?> GetContactAsync(int id);
}

Consider the following ASP.NET Core controller that uses this session:

[ApiController]
[Route("api/contacts")]
public sealed class GetContactController : ControllerBase
{
    private readonly IAsyncFactory<IGetContactSession> _sessionFactory;

    public GetContactController(IAsyncFactory<IGetContactSession> sessionFactory) =>
        _sessionFactory = sessionFactory;

    [HttpGet("{id}")]
    public async Task<ActionResult<Contact>> GetContact(int id)
    {
        if (id < 1)
        {
            ModelState.AddModelError("id", "The id must at least be 1");
            return ValidationProblem();
        }

        await using var session = await _sessionFactory.CreateAsync();
        var contact = await session.GetContactAsync(id);
        if (contact == null)
        {
            return NotFound();
        }

        return contact;
    }
}

You could then test your controller with the following code in xunit:

public sealed class GetContactControllerTests
{
    private readonly GetContactSessionMock _session;
    private readonly GetContactController _controller;

    public GetContactControllerTests()
    {
        _session = new GetContactSessionMock();
        var sessionFactory = new AsyncFactoryMock<IGetContactSession>(_session);
        _controller = new GetContactController(sessionFactory);
    }

    [Fact]
    public async Task MustReturnContactWhenIdIsValid()
    {
        _session.Contact = new Contact();

        var result = await _controller.GetContact(42);

        Assert.Equal(_session.Contact, result.Value);
        _session.MustBeDisposed(); // Use this to check if your controller properly disposed the session
    }

    [Fact]
    public async Task MustReturnNotFoundWhenIdIsNotExisting()
    {
        var result = await _controller.GetContact(13);

        Assert.IsType<NotFoundResult>(result.Result);
        _session.MustBeDisposed();
    }

    // AsyncReadOnlySessionMock automatically implements IAsyncDisposable for you
    private sealed class GetContactSessionMock : AsyncDisposableMock, IGetContactSession
    {
        public Contact? Contact { get; set; }

        public Task<Contact?> GetContactAsync(int id) => Task.FromResult(Contact);
    }


}

public sealed class AsyncFactoryMock<T> : IAsyncFactory<T>
        where T : IAsyncDisposable
{
    private readonly T _session;

    public AsyncFactoryMock(T session) => _session = session;

    public Task<T> CreateAsync() => Task.FromResult(_session);
}

In the above unit tests, the GetContactSessionMock derives from AsyncDisposableMock which automatically implements IAsyncDisposable and tracks proper disposal of the session. You can use the MustBeDisposed method to check that the controller properly closed the session.

Mocking sessions

If your session manipulates data and thus implements ISession for transactional support, you can derive your mocks from the SessionMock base class. The following example for updating an existing contact shows this in action:

public interface IUpdateContactSession : ISession
{
    Task<Contact?> GetContactAsync(int id);
}

The controller that uses this session might look like this:

[ApiController]
[Route("api/contacts/update")]
public sealed class UpdateContactController : ControllerBase
{
    private readonly IAsyncFactory<IUpdateContactSession> _sessionFactory;
    private readonly UpdateContactDtoValidator _validator;

    public UpdateContactController(IAsyncFactory<IUpdateContactSession> sessionFactory,
                                   UpdateContactDtoValidator validator)
    {
        _sessionFactory = sessionFactory;
        _validator = validator;
    }

    [HttpPut]
    public async Task<IActionResult> UpdateContact(UpdateContactDto dto)
    {
        if (this.CheckForErrors(dto, _validator, out var badResult))
        {
            return badResult;
        }

        await using var session = await _sessionFactory.CreateAsync();
        var contact = await session.GetContactAsync(dto.ContactId);
        if (contact == null)
        {
            return NotFound();
        }

        dto.UpdateContact(contact);
        await session.SaveChangesAsync();
        return NoContent();
    }
}

To test this controller, we might write the following unit tests in xunit:

public sealed class UpdateContactControllerTests
{
    private readonly UpdateContactSessionMock _session;
    private readonly UpdateContactController _controller;

    public UpdateContactControllerTests()
    {
        _session = new UpdateContactSessionMock();
        var sessionFactory = new AsyncFactoryMock<IUpdateContactSession>(_session);
        _controller = new UpdateContactController(sessionFactory, new UpdateContactDtoValidator());
    }

    [Fact]
    public async Task UpdateEntityWhenIdIsValid()
    {
        var contact = new Contact { Id = 1, Name = "John Doe" };
        _session.Contact = contact;
        var dto = new UpdateContactDto(1, "Jane Doe");

        var result = await _controller.UpdateContact(dto);

        Assert.Equal("Jane Doe", contact.Name);
        Assert.IsType<NoContentResult>(result.Result);
        _session.SaveChangesMustHaveBeenCalled() // Use this method to ensure SaveChangesAsync was called
                .MustBeDisposed();
    }

    [Fact]
    public async Task RefuseUpdateWhenIdIsNonExisting()
    {
        var dto = new UpdateContactDto(42, "Buzz Greenfield");

        var result = await _controller.UpdateContact(dto);

        Assert.IsType<NotFoundResult>(result.Result);
        _session.SaveChangesMustNotHaveBeenCalled() // Use this method to ensure that SaveChangesAsync was NOT called
                .MustBeDisposed();
    }

    private sealed class UpdateContactSessionMock : SessionMock, IUpdateContactSession
    {
        public Contact? Contact { get; set; }

        public Task<Contact?> GetContactAsync(int id) => Task.FromResult(Contact);
    }
}

In the above unit test, UpdateContactSessionMock derives from SessionMock which implements ISession and tracks calls to SaveChangesAsync and DiposeAsync. The methods SaveChangesMustHaveBeenCalled and SaveChangesMustNotHaveBeenCalled are used to ensure that SaveChangesAsync is properly called by the UpdateContactController.

By the way, you can throw an arbitrary exception during SaveChanges by setting the ExceptionOnSaveChanges property.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  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 was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos 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
3.0.0 143 4/1/2025
2.0.0 194 6/13/2024
1.0.0 235 12/20/2022

Light.DataAccessMocks 3.0.0
--------------------------------

- updated support for Light.SharedCore 3.0.0
- read all docs at https://github.com/feO2x/Light.DataAccessMocks