Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call constructor with interface arguments when mocking a concrete class with Moq

I have the following class, which uses constructor injection:

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

For most methods in this class, I simply create Moq mocks for IRepository and IProvider and construct the Service. However, there is one method in the class that calls several other methods in the same class. For testing this method, instead of testing all those methods together, I want to test that the method calls those methods correctly and processes their return values correctly.

The best way to do this is to mock Service. I've mocked concrete classes with Moq before without issue. I've even mocked concrete classes that require constructor arguments with Moq without issue. However, this is the first time I've needed to pass mocked arguments into the constructor for a mocked object. Naturally, I tried to do it this way:

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

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

However, that does not work. Instead, I get the following error:

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

This works fine if Service's constructor takes simple arguments like ints and strings, but not if it takes interfaces that I'm mocking. How do you do this?

like image 793
Nick Williams Avatar asked Apr 18 '14 14:04

Nick Williams


2 Answers

Why are you mocking the service you are testing? If you are wishing to test the implementation of the Service class (whether that be calls to mocked objects or not), all you need are mocks for the two interfaces, not the test class.

Instead of:

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

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

Shouldn't it be this instead?

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

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

I realize that it is possible to mock concrete objects in some frameworks, but what is your intended purpose? The idea behind mocking something is to remove the actual implementation so that it does not influence your test. But in your question, you have stated that you wish to know that certain classes are called on properly, and then you wish to validate the results of those actions. That is undoubtedly testing the implementation, and for that reason, I am having a hard time seeing the goals of mocking the concrete object.

like image 82
JesseNewman19 Avatar answered Oct 31 '22 21:10

JesseNewman19


I had a very similar problem when my equivalent of Service had an internal constructor, so it was not visible to Moq.

I added

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

to my AssemblyInfo.cs file for the implementing project. Not sure if it is relevant, but I wanted to add a suggestion on the off chance that it helps you or someone else.

like image 5
Jonny Avatar answered Oct 31 '22 23:10

Jonny