Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it recommended to mock concrete class?

Most of the examples given in mocking framework website is to mock Interface. Let say NSubstitute that I'm currently using, all their mocking examples is to mock interface.

But in reality, I saw some developer mock concrete class instead. Is it recommended to mock concrete class?

like image 607
DonDon Avatar asked Aug 29 '12 09:08

DonDon


People also ask

When should we mock a class?

4 Answers. Show activity on this post. Mock objects are useful when you want to test interactions between a class under test and a particular interface. For example, we want to test that method sendInvitations(MailServer mailServer) calls MailServer.

What does mock class mean?

A typical stub is a database connection that allows you to mimic any scenario without having a real database. A mock is a fake class that can be examined after the test is finished for its interactions with the class under test. For example, you can ask it whether a method was called or how many times it was called.

What means concrete class?

A concrete class is a class that has an implementation for all of its methods. They cannot have any unimplemented methods. It can also extend an abstract class or implement an interface as long as it implements all their methods. It is a complete class and can be instantiated.


1 Answers

In theory there is absolutely no problem mocking a concrete class; we are testing against a logical interface (rather than a keyword interface), and it does not matter whether that logical interface is provided by a class or interface.

In practice .NET/C# makes this a bit problematic. As you mentioned a .NET mocking framework I'm going to assume you're restricted to that.

In .NET/C# members are non-virtual by default, so any proxy-based methods of mocking behaviour (i.e. derive from the class, and override all the members to do test-specific stuff) will not work unless you explicitly mark the members as virtual. This leads to a problem: you are using an instance of a mocked class that is meant to be completely safe in your unit test (i.e. won't run any real code), but unless you have made sure everything is virtual you may end up with a mix of real and mocked code running (this can be especially problematic if there is constructor logic, which always runs, and is compounded if there are other concrete dependencies to be new'd up).

There are a few ways to work around this.

  • Use interfaces. This works and is what we advise in the NSubstitute documentation, but has the downside of potentially bloating your codebase with interfaces that may not actually be needed. Arguably if we find good abstractions in our code we'll naturally end up with neat, reusable interfaces we can test to. I haven't quite seen it pan out like that, but YMMV. :)
  • Diligently go around making everything virtual. An arguable downside to this is that we're suggesting all these members are intended to be extension points in our design, when we really just want to change the behaviour of the whole class for testing. It also doesn't stop constructor logic running, nor does it help if the concrete class requires other dependencies.
  • Use assembly re-writing via something like the Virtuosity add-in for Fody, which you can use to modify all class members in your assembly to be virtual.
  • Use a non-proxy based mocking library like TypeMock (paid), JustMock (paid), Microsoft Fakes (requires VS Ultimate/Enterprise, though its predecessor, Microsoft Moles, is free) or Prig (free + open source). I believe these are able to mock all aspects of classes, as well as static members.

A common complaint lodged against the last idea is that you are testing via a "fake" seam; we are going outside the mechanisms normally used for extending code to change the behaviour of our code. Needing to go outside these mechanisms could indicate rigidity in our design. I understand this argument, but I've seen cases where the noise of creating another interface/s outweighs the benefits. I guess it's a matter of being aware of the potential design issue; if you don't need that feedback from the tests to highlight design rigidity then they're great solutions.

A final idea I'll throw out there is to play around with changing the size of the units in our tests. Typically we have a single class as a unit. If we have a number of cohesive classes as our unit, and have interfaces acting as a well-defined boundary around that component, then we can avoid having to mock as many classes and instead just mock over a more stable boundary. This can make our tests a more complicated, with the advantage that we're testing a cohesive unit of functionality and being encouraged to develop solid interfaces around that unit.

Hope this helps.

like image 76
David Tchepak Avatar answered Sep 24 '22 01:09

David Tchepak