How to mock a class that implements multiple interfaces

前端 未结 4 772
误落风尘
误落风尘 2020-12-05 17:19

How to mock the following class:

UserRepository : GenericRepository, IUserRepository


public class GenericRepository : IGenericRe         


        
相关标签:
4条回答
  • 2020-12-05 17:38

    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);
    
    }
    
    0 讨论(0)
  • 2020-12-05 17:45

    You don't mock classes, you mock interfaces. In your case you could have two mocks - one that mocks IUserRepository and one that mocks IGenericRepository<User>. They shouldn't necessarily be the same object - if they DO have to be the same object, then it may be a design flaw.

    0 讨论(0)
  • 2020-12-05 17:52

    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.

    0 讨论(0)
  • 2020-12-05 17:58

    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());
    
    0 讨论(0)
提交回复
热议问题