如何模拟实现多个接口的类

问题描述 投票:0回答:5

如何模拟以下类:

UserRepository : GenericRepository<User>, IUserRepository


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

我正在使用Moq,我很困惑如何正确处理多个接口。

c# mocking moq
5个回答
125
投票

看看https://github.com/Moq/moq4/wiki/Quickstart

高级功能

// 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());

31
投票

Moq 内置了一种处理多个接口的机制。

假设我们有一个接口 IFoo 和相同的 Foo 的实现。我们还有使用 IFoo 的ClientOne

然后我们有一个接口 IFooBar : IFoo,一个实现 FooBar : Foo, IFooBar 和一个使用 IFooBar 的 ClientTwo

为系统创建端到端测试时,我们有一个 IFooBarClientOneClientTwoAs<>() 函数允许我们将 Mock 用作 Mock

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);

}

3
投票

如果我正确理解了这个问题,您需要有一个

UserRepository
的模拟实例,并且出于测试目的,设置对来自
IGenericRepository<TEntity>
接口和
IUserRepository
接口的方法的调用。

您可以使用单个模拟实例实现多个接口,如下所示:

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);

但是,正如 D Stanley 指出的,需要这样做可能表明您的设计存在缺陷。


1
投票

您可以花一点时间声明一个仅用于测试的通用接口,例如:

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());
    }
}

0
投票
Generate an interface that inherits the interfaces you want to mock, e.g.

public interface IFakeMyInterface<IEntity> : IGenericRepository<TEntity>, IUserRepository
{}

public interface IGenericRepository<TEntity>
{
    TEntity Method1();
}

public interface IUserRepository
{
    string Method2();
}

public class yourClass
{
    public IGenericRepository<TEntity> Repo { get; set;}
}

class SomeTest
{
    public void DoTest()
    {
        Mock<IFakeMyInterface<IEntity>> mock = new Mock<IFakeMyInterface<IEntity>>();
        mock.As<IGenericRepository<TEntity>>().Setup(f => f.Method1()).Returns(some_TEntity);
        mock.As<IUserRepository>().Setup(f => f.Method2()).Returns("sdsd4s5d454fd5sd");
        
        var oTarget = new yourClass();
        
        oTarget.Repo = mock.As<IGenericRepository<TEntity>>().Object;

    }
}
© www.soinside.com 2019 - 2024. All rights reserved.