2

I am trying to mock certain methods of a class, while keeping the true implementation of other methods.

Now, I did find something related on stackoverflow here. However, none of the suggested answers help me.

Lee's answer is probably good in most cases, but it is inappropriate in my case as I really need to mock an Interface (which has various implementation) and not the class itself.

Brandon's answer is very close, but I found the following hick up.
Here is his code pasted for convenience:

var mock = new Mock<ITestClass>(); // Create Mock of interface

// Create instance of ITestClass implementation you want to use
var inst = new ActualTestClass();

// Setup to call method of an actual instance
// if method returns void use mock.Setup(...).Callback(...)
mock.Setup(m => m.SomeMethod(It.IsAny<int>())
    .Returns((int x) => inst.SomeMethod(x));

What is causing me problem is that this example works for simple scenarios, but it won't work if "SomeMethod()" it to call another method from ITestClass that has a mock setup. In that case "SomeMethod()" will still use the real implementation.

For clarity:
Say ITestClass implements the methods SomeMethod and SomeOtherMethod. The former must call the latter that is mocked as per:

mock.Setup(m => m.SomeOtherMethod(It.IsAny<bool>())
     .Returns(true);

Now how can this mock be used by SomeMethod instead of the real implementation?

EDIT

Another reason why I need to mock an interface and not the class itself is that the latter option will not allow you to test TestClass() if it were to be a singleton.

stackMeUp
  • 522
  • 4
  • 16
  • If I understand well, you want to mock a method of the same class you are testing, not a dependency inside the method, but the whole method. My question is why are you doing that? – insane_developer Aug 18 '20 at 16:45
  • It's not entirely clear why lee's answer doesn't help you in this case. What is preventing you from doing the 'partial setup' as specified in that answer? You're expecting to use an existing implementation for certain methods, but mock the interface in others. Barring additional information on what makes that infeasible/undesirable, the partial mock seems the best answer for that scenario. – Jeff Dammeyer Aug 18 '20 at 16:45
  • @insane_developer, in my system "SomeOtherMethod" would interacting with some Hardware, but I don't want it to happen, which is why it has to be mocked. – stackMeUp Aug 18 '20 at 18:00
  • @JeffDammeyer, as mentioned in my question, I have to mock the interface, not the class. I have more than 1 class implementing the interface, which are all potentially instantiated by that method – stackMeUp Aug 18 '20 at 18:03
  • @stackMeUp that is what I suspected. In terms of class design, that method should be part of another class that acts as a dependency of the class you are testing. That would make this easily testable, or put another way, testable the way it's supposed to be. – insane_developer Aug 18 '20 at 18:04
  • @insane_developer, I already tried to reshape things, but I could not think of something better that helped me testing. I will give it another go, thanks :-) – stackMeUp Aug 18 '20 at 18:06
  • 1
    @stackMeUp encapsulate all dependencies in their own classes, and you will not have this issue again. You decide whether you want to refactor code to support good unit testing, or resort to some kind of hack to make the tests pass. – insane_developer Aug 18 '20 at 18:18
  • 1
    @stackMeUp Having code in the question closer to what your actual design looks like would help with more relevant suggestions. Otherwise, as @insane_developer suggested, redesign these classes to decouple the two concerns. Using different classes/interfaces for each responsibility (`SomeMethod` vs `SomeOtherMethod`) would let you easily replace one while keeping the implementation of the other. – Jeff Dammeyer Aug 18 '20 at 18:27
  • Thanks guys, I will follow your advice and try to come up with something more testable :-) – stackMeUp Aug 18 '20 at 18:32
  • @insane_developer, I have added an edit. I think I have no choice, but to find a different work around as I need to test a singleton class – stackMeUp Aug 19 '20 at 13:57
  • 1
    @stackMeUp whether you have no choice, I can't say because I don't know your application. It's possible that you don't understand how testable code is supposed to look like, for which there are plenty of resources online. Or, perhaps the application is so test-unfriendly that you can't even do the right thing without massive changes that could cause even more problems. I think you've been given clear hints here, if the former is true. – insane_developer Aug 19 '20 at 15:43
  • 1
    This is impossible with a _constrained_ isolating framework such as Moq, NSubstitute, or FakeItEasy. But this is possible with _unconstrained_ frameworks: TypeMock, JustMock, MS Fakes - all are paid. I can give you an example of a solution using the free Pose library that will allow you to do this. – Alexander Petrov Aug 19 '20 at 17:15
  • Thanks @AlexanderPetrov. I thought Moq was the standard, but I don't mind using something else if you thing there is a better option out there? Is there one from your list that comes out of the lot? – stackMeUp Aug 20 '20 at 09:23

2 Answers2

1

Popular isolation frameworks such as Moq, NSubstitute, or FakeItEasy are constrained. Impossible solve your problem with them.

There are also unconstrained isolation frameworks: TypeMock, JustMock (both are paid) and MS Fakes (available only in VS Enterprise).

However, I recently came across an interesting free Pose library that will solve your problem.

Add package.

Open namespace:

using Pose;

Test code:

var inst = new ActualTestClass();

Shim testClassShim = Shim.Replace(() => inst.SomeOtherMethod(Is.A<bool>()))
    .With((ActualTestClass _, bool b) => true);

int actual = 0;

PoseContext.Isolate(() =>
{
    actual = inst.SomeMethod(1); // it will use shim inside
},
testClassShim);

Assert.Equal(0, actual);

But it is still much inferior in many ways to its commercial counterparts.

It should be noted that unconstrained tools, although they solve isolation problems extremely effectively, but in this way they forgive design errors, which can eventually lead to poor application architecture.

Alexander Petrov
  • 13,457
  • 2
  • 20
  • 49
  • Thanks for that. I will check it out. Maybe I could use one of these for this specific test/issue I am having and stick to Moq for the rest. I'll mark your answer as accepted answer if nobody can suggest an alternative using Moq within the next few days. – stackMeUp Aug 20 '20 at 11:47
  • 1
    Just wanted to mention that JustMock has a free version named JustMock Lite. The free version is comparable with Moq and you could use it for most of the tests and use the commercial version only where needed. Disclaimer: I am one of the developers behind JustMock. – Mihail Vladov Oct 22 '20 at 12:00
1

How about not using Moq at all?
You could create a wrapper class that derives from your main class and overrides the methods you want to mock with whatever you need.
Then use this derived class in your test.
Of course these overriden methods could use Moq or be defined as mocks from within this derived class.

toughQuestions
  • 161
  • 1
  • 8