Подтвердить что ты не робот

Как издеваться над классом, который реализует несколько интерфейсов

Как издеваться над следующим классом:

UserRepository : GenericRepository<User>, IUserRepository


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

Я использую Moq, и я смущен, как правильно обрабатывать несколько интерфейсов.

4b9b3361

Ответ 1

Взгляните на 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());

Ответ 2

В Moq встроен механизм для работы с несколькими интерфейсами.

Скажем, у нас есть интерфейс IFoo и реализация того же Foo. У нас также есть ClientOne, который использует IFoo.

Затем мы имеем интерфейс IFooBar: IFoo, реализацию FooBar: Foo, IFooBar и ClientTwo, которая использует IFooBar.

При создании сквозного теста для системы мы имеем IFooBar, ClientOne и ClientTwo. Функция As < > () позволяет использовать Mock <IFooBar> как 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);

}

Ответ 3

Вы не издеваетесь над классами, вы издеваетесь над интерфейсами. В вашем случае у вас может быть два макета - тот, который высмеивает IUserRepository, и тот, который издевается IGenericRepository<User>. Они не обязательно должны быть одним и тем же объектом - если они должны быть одним и тем же объектом, тогда это может быть дефект дизайна.

Ответ 4

Если я правильно понял вопрос, вы хотите иметь один макетный экземпляр UserRepository, а в целях тестирования, настраивать вызовы методов из интерфейса IGenericRepository<TEntity> и интерфейса IUserRepository.

Вы можете реализовать несколько интерфейсов с помощью одного экземпляра mock, например:

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

Однако, как отметил Д. Стэнли, необходимость сделать это, вероятно, является признаком того, что в вашем дизайне есть недостаток.