.netnsubstituteardalis-specification

Mock a call to a Repository that uses Ardalis Specification


I have a generic Repository (RepositoryBase) that gets queried using a specification

Specification

public sealed class ProductByIdSpec : SingleResultSpecification<Product>
{
    public ProductByIdSpec (int id)
    {
        Query
     
            .Where(p => p.Id == id);
    }

  
}

I then used NSubstitute to mock the repository in unittests.

  _productRepository = Substitute.For<IReadRepositoryBase<Product>>();

I can use the generic matcher to return a Product

    _assetRepository.SingleOrDefaultAsync( 
            
            Arg.Any<ProductByIdSpec>())
        .Returns(product);

The Product is then retrieved by calling

_productRepository.SingleOrDefaultAsync(new ProductByIdSpec(42));

I dont find a way to set up a matcher that takes into account the id

I tried

_productRepository.SingleOrDefaultAsync( Arg.Is(new ProductByIdSpec(42))
         .Returns(product);

But this does return null with

_productRepository.SingleOrDefaultAsync(new ProductByIdSpec(42));

I get it that at some point there needs to be a comparison of two instances of new ProductByIdSpec(42) which does not work for me.

I tried top use a lambda but dont find a way for getting the "42" in the object new ProductByIdSpec(42)

_productRepository.SingleOrDefaultAsync( 
            
            Arg.Is<ProductByIdSpec>(x => x.SearchCriterias ??????))
        .Returns(product);

Is there a way to use Ardalis Specification together with NSubstitute for the case I showed?


Solution

  • You need to save the id as a public property in the spec:

    public sealed class ProductByIdSpec : SingleResultSpecification<Product>
    {
        public int Id { get; }
        public ProductByIdSpec(int id)
        {
            Id = id;
            Query.Where(p => p.Id == id);
        }
    }
    

    Then in the test just do:

    _productRepository.SingleOrDefaultAsync(
        Arg.Is<ProductByIdSpec>(x => x.Id == 42)
    ).Returns(product);
    

    Now it works.