Как вызвать конструктор с аргументами интерфейса при имитации конкретного класса с помощью Moq

У меня есть следующий класс, который использует внедрение конструктора:

public class Service : IService
{
    public Service(IRepository repository, IProvider provider) { ... }
}

Для большинства методов этого класса я просто создаю макеты Moq для IRepository и IProvider и конструирую Service. Однако в классе есть один метод, который вызывает несколько других методов того же класса. Для тестирования этого метода вместо тестирования всех этих методов вместе я хочу проверить, правильно ли метод вызывает эти методы и правильно обрабатывает их возвращаемые значения.

Лучший способ сделать это - издеваться над Service. Раньше я без проблем издевался над конкретными классами с помощью Moq. Я даже издевался над конкретными классами, которые требуют аргументов конструктора с Moq без проблем. Однако мне впервые потребовалось передать имитируемые аргументы в конструктор имитируемого объекта. Естественно, я пытался сделать это так:

var repository = new Mock<IRepository>();
var provider = new Mock<IProvider>();

var service = new Mock<Service>(repository.Object, provider.Object);

Однако это не работает. Вместо этого я получаю следующую ошибку:

Castle.DynamicProxy.InvalidProxyConstructorArgumentsException : Can not instantiate proxy of class: My.Namespace.Service.
Could not find a constructor that would match given arguments:
    Castle.Proxies.IRepository
    Castle.Proxies.IProvider

Это нормально работает, если конструктор Service принимает простые аргументы, такие как ints и strings, но не принимает интерфейсы, над которыми я издеваюсь. Как ты делаешь это?


person Nick Williams    schedule 18.04.2014    source источник
comment
Какую версию Moq и Castle вы используете? Поскольку ваш пример кода отлично работает с Moq 4.2.1312.1622 и Castle.Core 3.2.2 ...   -  person nemesv    schedule 18.04.2014


Ответы (3)


Почему вы издеваетесь над сервисом, который тестируете? Если вы хотите протестировать реализацию класса Service (будь то вызовы имитируемых объектов или нет), все, что вам нужно, это макеты для двух интерфейсов, а не для тестового класса.

Вместо того:

var repository = new Mock<IRepository>();
var provider = new Mock<IProvider>();

var service = new Mock<Service>(repository.Object, provider.Object);

Разве это не должно быть вместо этого?

var repository = new Mock<IRepository>();
var provider = new Mock<IProvider>();

var service = new Service(repository.Object, provider.Object);

Я понимаю, что в некоторых фреймворках возможно имитировать конкретные объекты, но какова ваша цель? Идея имитации чего-либо состоит в том, чтобы удалить реальную реализацию, чтобы она не влияла на ваш тест. Но в своем вопросе вы заявили, что хотите знать, что определенные классы вызываются правильно, а затем вы хотите проверить результаты этих действий. Это, несомненно, проверка реализации, и по этой причине мне трудно понять цели имитации конкретного объекта.

person JesseNewman19    schedule 05.10.2015

У меня была очень похожая проблема, когда у моего эквивалента Service был внутренний конструктор, поэтому он не был виден Moq.

я добавил

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

в мой файл AssemblyInfo.cs для реализуемого проекта. Не уверен, что это актуально, но я хотел добавить предложение на случай, если оно поможет вам или кому-то другому.

person Jonny    schedule 04.11.2014

Это должно быть проблема старой версии, с последней версией все в порядке. Ник, пожалуйста, проверьте!

P.s .: Я начал баунти по ошибке (у меня была неправильная подпись в конструкторе).

person Dzianis Yafimau    schedule 04.10.2015