Prash's Blog

Mocking internal methods with Moq in C# September 25, 2012

Filed under: Uncategorized — prazjain @ 12:20 pm
Tags: , ,

I have been using Moq for some time now and love it, but had one frustrating nag, that I could not moq internal methods for some reason.
But after several frustrating hours of figuring out how to moq internal methods in moq. This is how I did it.

In the assemblyinfo.cs file for the project (that has the source you want to test).
Add a line as below :

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

Interesting thing to note here is that to mock internal method it must be virtual. eg:

internal MI5Employee Search(string name)
{
    // other methods like this one will call the virtual method, so the virtual method can be mocked when this method is being tested.
    int id = GetEmployeeId(name);
    // next id is used below to do some other work.

   return myEmpObj;
}
internal virtual int GetEmployeeId(string name) { .. }

So for a method like this in Moq, you can mock it like this :

var mi5EmployeeMock = new Mock<MI5Employee>();
mi5EmployeeMock.SetUp(mi5EmployeeMock.GetEmployeeId("prash")).Returns(007);
// now the method is setup and any method you are testing that makes this method call internally then it will return 7. 
MI5Employee emp = mi5EmployeeMock.Object.Search("prash");
// this test will pass
Assert.IsTrue(emp.Id== 7); 

Now the tricky part is, if your class does not have an interface and you have to test the same method.

var mi5EmployeeMock = new Mock<MI5Employee>();
// lets assume all its dependencies are set up here
int res = mi5EmployeeMock.Object.GetEmployeeId("prash");
// this test will fail
Assert.IsTrue(res == 7, "This test fails to find James Bond!");

Here the test will fail, as res will have value 0, that is because the method GetEmployeeId is set as virtual and Moq cannot test virtual methods, it just will not call its actual implementation.
So though we are able to unit test Seach method we are not able to unit test GetEmployeeId method using Moq.
The way I got around it is by having another implementation that is non virtual and calling that from the virtual method. eg.

internal MI5Employee Search(string name)
{
    // other methods like this one will call the virtual method, so the virtual method can be mocked when this method is being tested.
    int id = GetEmployeeId(name);
    // next id is used below to do some other work.

   return myEmpObj;
}
// this method is used for mocking and called directly by other methods.
internal virtual int GetEmployeeId(string name) 
{
   return GetEmployeeId_NonVirtual(name);
}
// this method exists solely for testing GetEmployeeId logic using Moq.
internal int GetEmployeeId_NonVirtual(string name) { .. }

So our test case will look a bit like this :

var mi5EmployeeMock = new Mock<MI5Employee>();
// lets assume all its dependencies are set up here
int res = mi5EmployeeMock.Object.GetEmployeeId_NonVirtual("prash");
// this test will pass
Assert.IsTrue(res == 7);

This may not be elegant but it works and I get test all my code. Green is Good.

Advertisements
 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s