mercredi 25 novembre 2015

Struggling to Mock EF 6 DbSet With NSubstute

I've scoured many blog and forum posts over the past few hours and have been very frustrated trying to mock out a DbSet using NSubstitute. All solutions I've tried on stack overflow don't work for me. My latest attempt is below with the test output. I'd really appreciate it if anyone could lend me their expertise to help with this, I'm new to Unit Testing.

The method under test (_context is my derived DbContext instance):

public void Insert<T>(T entity) where T : class
{
      _context.Set<T>().Add(entity);
}

So I'm testing the above method initially just to see if it calls my context.Set().Add() method when called.

The Test Method:

[TestMethod]
public void Insert_WhenCalled_CallsIIOInterfaceEntitiesSetAdd()
{
       _context = Substitute.For<IIOInterfaceEntities>();
        SetupContextWithSubstituteDbSet();
        var repositoryUnderTest = new IoInterfaceRepository(_context);
        var entity = new Activity();

        repositoryUnderTest.Insert(entity);

        _context.Received().Set<Activity>().Add(Arg.Any<Activity>());
}

The substitute setup:

private void SetupContextWithSubstituteDbSet()
{
        var collection = new List<Activity>().AsQueryable();
        var substituteSet = Substitute.For<IDbSet<Activity>>();
        substituteSet.Provider.Returns(collection.Provider);
        substituteSet.Expression.Returns(collection.Expression);
        substituteSet.ElementType.Returns(collection.ElementType);
                 substituteSet.GetEnumerator().Returns(collection.GetEnumerator());

        _context.Activities.Returns(substituteSet);
}

The DbContext derived type interface:

public interface IIOInterfaceEntities
{
        DbSet<Activity> Activities { get; set; }

        DbSet<TEntity> Set<TEntity>() where TEntity : class;
        Task<int> SaveChangesAsync();
}

Test Name: Insert_WhenCalled_CallsIIOInterfaceEntitiesSetAdd Test FullName: IOInterfaceModelUnitTests.IoInterfaceRepositoryTests.Insert_WhenCalled_CallsIIOInterfaceEntitiesSetAdd Test Source: c:\Dev\Playground\Source\IOInterfaceModel\IOInterfaceModelUnitTests\IoInterfaceRepositoryTests.cs : line 31 Test Outcome: Failed Test Duration: 0:00:00.0372501

Result Message: Test method IOInterfaceModelUnitTests.IoInterfaceRepositoryTests.Insert_WhenCalled_CallsIIOInterfaceEntitiesSetAdd threw exception: NSubstitute.Exceptions.CouldNotSetReturnDueToTypeMismatchException: Can not return value of type IDbSet1Proxy for IIOInterfaceEntities.get_Activities (expected type DbSet1).

Make sure you called Returns() after calling your substitute (for example: mySub.SomeMethod().Returns(value)), and that you are not configuring other substitutes within Returns() (for example, avoid this: mySub.SomeMethod().Returns(ConfigOtherSub())).

If you substituted for a class rather than an interface, check that the call to your substitute was on a virtual/abstract member. Return values cannot be configured for non-virtual/non-abstract members.

Correct use: mySub.SomeMethod().Returns(returnValue);

Potentially problematic use: mySub.SomeMethod().Returns(ConfigOtherSub()); Instead try: var returnValue = ConfigOtherSub(); mySub.SomeMethod().Returns(returnValue); Result StackTrace:
at NSubstitute.Core.ConfigureCall.CheckResultIsCompatibleWithCall(IReturn valueToReturn, ICallSpecification spec) at NSubstitute.Core.ConfigureCall.SetResultForLastCall(IReturn valueToReturn, MatchArgs matchArgs) at NSubstitute.Core.CallRouter.LastCallShouldReturn(IReturn returnValue, MatchArgs matchArgs) at NSubstitute.Core.SubstitutionContext.LastCallShouldReturn(IReturn value, MatchArgs matchArgs) at NSubstitute.SubstituteExtensions.Returns[T](MatchArgs matchArgs, T returnThis, T[] returnThese) at NSubstitute.SubstituteExtensions.Returns[T](T value, T returnThis, T[] returnThese) at IOInterfaceModelUnitTests.IoInterfaceRepositoryTests.SetupContextWithSubstituteDbSet() in c:\Dev\Playground\Source\IOInterfaceModel\IOInterfaceModelUnitTests\IoInterfaceRepositoryTests.cs:line 56 at IOInterfaceModelUnitTests.IoInterfaceRepositoryTests.Insert_WhenCalled_CallsIIOInterfaceEntitiesSetAdd() in c:\Dev\Playground\Source\IOInterfaceModel\IOInterfaceModelUnitTests\IoInterfaceRepositoryTests.cs:line 33

Aucun commentaire:

Enregistrer un commentaire