67

How to mock the following class:

UserRepository : GenericRepository<User>, IUserRepository


public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class

I am using Moq, and I am confused how to handle multiple interfaces correctly.

loyalflow
  • 14,275
  • 27
  • 107
  • 168
  • Is there a relationship between `IUserRepository` and `IGenericRepository`? Is it required that an object that implements `IUserRepository` also implement `IGenericRepository`? – D Stanley Apr 04 '13 at 20:06
  • What does the production code you're trying to test look like? – Jon Skeet Apr 04 '13 at 20:07

4 Answers4

120

Take a look at https://github.com/Moq/moq4/wiki/Quickstart

Advanced Features

// implementing multiple interfaces in mock
var foo = new Mock<IFoo>();
var disposableFoo = foo.As<IDisposable>();
// now IFoo mock also implements IDisposable :)
disposableFoo.Setup(df => df.Dispose());
ShloEmi
  • 1,851
  • 2
  • 20
  • 25
  • 10
    Adding to the this answer, if you need to pass the mock to a method that take IFoo, you can also switch IFoo and IDisposable, ie: var disposableFoo = new Mock(); var foo = disposableFoo.As(); – Quad Coders Sep 27 '16 at 21:06
  • Or create a new interface for the test: ```public interface IDisposableFoo : IFoo, IDisposable``` – BalintPogatsa Jan 20 '20 at 15:25
  • What about with `Mock.Of()`? Is there a solution for it or I gotta refactor? – jeromej Aug 10 '21 at 12:53
  • @jeromej - can you please elaborate the question, ty. – ShloEmi Aug 10 '21 at 13:33
  • @ShloEmi I was wondering if there was a version using the short-hand version of `Mock.Of<>` (which returns the object directly) but there isn't. – jeromej Aug 10 '21 at 14:28
  • @jeromej - maybe this will help a bit? var disposableFoo = new Mock().As(); – ShloEmi Aug 15 '21 at 12:57
30

There is a mechanism built into Moq for dealing with multiple interfaces.

Say we have an interface IFoo and an implementation of the same Foo. We also have ClientOne that uses IFoo.

We then have an interface IFooBar : IFoo, an implementation FooBar : Foo, IFooBar and a ClientTwo that uses IFooBar.

When creating an end-to-end test for the system we have an IFooBar, ClientOne and ClientTwo. The As<>() function allows us to use the Mock<IFooBar> as a Mock<IFoo>.

public interface IFoo {
    int Id { get; }
}

public class Foo : IFoo {
    public int Id {
        get { return 1; }
    }
}

public interface IFooBar : IFoo  {
    string Name { get; }
}

public class FooBar : Foo, IFooBar {
    public string Name {
        get { return "AName"; }
    }
}

public class ClientOne {
    private readonly IFoo foo;

    public ClientOne(IFoo foo) {
        this.foo = foo;
    }

    public string Details {
        get { return string.Format("Foo : {0}", foo.Id); }
    }

}

public class ClientTwo {
    private readonly IFooBar fooBar;

    public ClientTwo(IFooBar fooBar) {
        this.fooBar = fooBar;
    }

    public string Details {
        get { return string.Format("Foo : {0}, Bar : {1}", fooBar.Id, fooBar.Name); }
    }

}


[TestMethod]
public void TestUsingBothClients() {

    var fooBarMock = new Mock<IFooBar>();
    var fooMock = fooBarMock.As<IFoo>();

    fooBarMock.SetupGet(mk => mk.Id).Returns(1);
    fooBarMock.SetupGet(mk => mk.Name).Returns("AName");

    var clientOne = new ClientOne(fooMock.Object);
    var clientTwo = new ClientTwo(fooBarMock.Object);

    Assert.AreEqual("Foo : 1", clientOne.Details);
    Assert.AreEqual("Foo : 1, Bar : AName", clientTwo.Details);

}
AlanT
  • 3,627
  • 20
  • 28
2

If I understand the question correctly, you want have a single mock instance of UserRepository, and for the purposes of a test, setup calls to methods from both the IGenericRepository<TEntity> interface and the IUserRepository interface.

You can implement multiple interfaces with a single mock instance like this:

var genericRepositoryMock = new Mock<IGenericRepository<User>>();
genericRepositoryMock.Setup(m => m.CallGenericRepositoryMethod()).Returns(false);

var userRepositoryMock = genericRepositoryMock.As<IUserRepository>();
userRepositoryMock.Setup(m => m.CallUserRepositoryMethod()).Returns(true);

However, as D Stanley pointed out, the need to do this is probably an indication that there is a flaw in your design.

Alex Peck
  • 4,603
  • 1
  • 33
  • 37
1

You can spare a bit with declaring a common interface just for testing, like:

interface IA { void Work(); }
interface IB { void Rest(); }

class AB: IA, IB
{
    public void Work() { ... }
    public void Rest() { ... }
}

interface IABTest : IA, IB
{}

class SomeTest
{
    public void DoTest()
    {
        var ab = new Mock<IABTest>();
        ab.Setup(m => m.Work());
        ab.Setup(m => m.Rest());
    }
}
CLS
  • 571
  • 5
  • 10