0

how can I obtain the equivalent of

Substitute.For<DbSet<MyClass>, IQueryable<MyClass>, IDbAsyncEnumerable>()

with machine.fakes? I tried using

var myFake = An<DbSet<MyClass>>();
myFake.WhenToldTo(m => ((IQueryable<MyClass>)m).Provider).Return(whatever);

but I get the following NotImplementedException:

The member 'IQueryable.Provider' has not been implemented on type 'DbSet`1Proxy' which 
inherits from 'DbSet`1'. Test doubles for 'DbSet`1' must provide implementations of 
methods and properties that are used.

The same exception raises with myFake.WhenToldTo(m => ((IQueryable)m).Provider).Return(whatever);

This is a class that reproduces the issue with minimal code. You need to add packages for Entity Framework, Machine.Specifications, Machie.Specifications.Should, Machine.Fakes, Machine.Fakes.NSubstitute, NSubstitute (or any other Mock Framework plugin)

using System.Data.Entity;
using System.Linq;
using Machine.Fakes;
using Machine.Specifications;

namespace SpecsTests
{
    public class TestClass
    {}

    [Subject("Test")]
    internal class TestSpecifications
    {
        [Subject("Test")]
        private class Test : WithFakes
        {
            private static int Count;
            private static DbSet<TestClass> Subject;

            private Establish context = () =>
                                        {
                                            var data = new [] { new TestClass() }.AsQueryable();
                                            Subject = An<DbSet<TestClass>>();

                                            Subject.WhenToldTo(m => ((IQueryable)m).Provider).Return( data.Provider);
                                        };

            private Because of = () => { Count = Subject.Count(); };

            private It Should_return_expected_results = () =>
                                                        {
                                                            Count.ShouldEqual(1);
                                                        };

        }
    }
}
  • I can get your code (without the cast) working. So the problem must be elsewhere. Can you show the rest of your code or the simplest not working example? – Simon Hohenadl Jan 13 '15 at 19:27
  • I improved the issue explanation. What do you mean with "without the cast"? if I don't cast to IQueryable in the lambda I get a compile error (cacnnot access explicit implementation of IQueryable.Provider) – Alessandro Lendaro Jan 14 '15 at 10:01
  • I am unable to analyze your problem without all the code that is executed, since your snippet works on my machine. Please provide the full spec and the declaration of DbSet. – Simon Hohenadl Jan 14 '15 at 14:41
  • DbSet is Entity Framework 6 System.Data.Entity.DbSet generic class. Creating the mock with An>() doesn't seem to implement the inherited interfaces (e.e. IQueryable), like NSubstitute' Substitute.For does – Alessandro Lendaro Jan 14 '15 at 15:07

1 Answers1

1

There is no way of faking more than one interface in one fake with Machine.Fakes - equivalent to NSubstitute's Substitute.For<>(). I see two options for you:

  1. Use NSubstitute directly.
    You can always do
    Subject = Substitute.For<DbSet<TestClass>, IQueryable<TestClass>>();
    instead of
    Subject = An<DbSet<TestClass>>();
    The drawbacks are that you give up the independence from the underlying mocking framework and Machine.Fake's automocking capabilities

  2. Restructure your code to fake only one interface at a time. This would be my preferred option.
    My first try with this would be to fake IDbSet<> instead of DbSet<> and work only against this interface. I know too little of what you are trying to achieve to give more detailed hints, however. As a general rule, you should always try to depend on interfaces. Maybe you can make the class under test independent of the concrete DbSet<>?

Simon Hohenadl
  • 502
  • 3
  • 8
  • I am using NSubstitute directly, though I'd prefer to abstract over it; – Alessandro Lendaro Jan 21 '15 at 08:30
  • I need to mock an IDbSet interface by mocking both the derived interfaces of IQueryable and IDbAsyncEnumerable, I don't think there is a way to mock those separately. However, multiple inheritance is a .NET feature so it should be featured by machine.fakes if it pretends to be an abstraction over mocking frameworks and not just an utility for automocking – Alessandro Lendaro Jan 21 '15 at 09:10
  • 1
    Thanks for your feedback. This is the first time I come across faking multiple interfaces in one fake. If multiple mocking frameworks support it, it could certainly be implemented in Machine.Fakes. I accept pull requests. :-) – Simon Hohenadl Jan 21 '15 at 12:44