Roy Osherove

View Original

The future of Isolation frameworks, and how Moq isn't it (for now)

In a past post I hinted that I think Moq is not a part of the future of isolation frameworks. Here’s where I get to explain why. To be clear, it is a really valuable, widely used framework, and it helped change the world of Isolation Frameworks in its day. It’s GOOD.

But it does not emcopass the properties that I’d like to see, and starting to see in the future of isolation frameworks. 

So, to be clear “the future” means “the future I think we should have”, and also, “the patterns I’m starting to see embraced that I like”.

TLDR:

  • The future is about usability. Moq has horrible messages, to the point of wasting lots of the devloper’s time.
  • The future is about testing a single concern. With Moq it’s easy to test too many things in a single test.
  • The future is cross-cutting, robust and future proof fakes. The newer frameworks allow (at least FakeItEasy) to do cross-cutting faking (such as on all methods that return a specific type).
  • The future is simplicity. (Moq is not as simple as the newer frameworks, in terms of API and usage)
  • The future is less confusing. The future APIs should not and do not use “Mock” and “stub” in the API, because these words are abused and over used to the point of namelessness. So they get out of the way, and not make you think to much about what you get back. It’s all about how you use it, anyway. (if you verify against it, it’s a mock. if not, it’s a stub. done.)
  • update: new: the future is loose, not strict. While mock does support loose mocks by default, it allows strict mocks, which make tests much more fragile. Newer frameworks are loose by default, with no strict mode that I know of.

See the video below for more details.

The LONG version:

 

  • The future is loose, not strict mocks. Loose mocks don’t care how many times something was called. so if you say that  method stub returns 3, it *always* returns 3. if you verify that a method was called, it doesn’t care how many times it was called with other parameters, as long as it was called at least once with the parameters you mentioned. this makes the tests more robust and future proof as well. Moq does support loose mocks by default, but like many others, it used to not, and still has support for strict mocks for backward compatibility. The new frameworks don’t support strict mocks by default at all, they just allow you to verify amount of times called if you really want to (which I still am not crazy about, but it’s a feature you’d need about 2% of the time when you do TDD).  Strict mocks expect you to say exactly how many times something will return something, or how many times something is called. Always. So your tests become very “naggy” and fragile every time you change production code and tweak it even a little bit. even if it still works in the end result, the tests will nag you to fix them, for all the wrong reasons.

 

  • The future is usabilityMoq has horrible error messages. When the test fails because Moq expectedsomething to be called and it wasn’t, or something different to be called than was actually was, there is almost no way to tell what the differences are in a simple way. The error messages are more scary than helpful. Worse yet, the error message usability has not had any work done that I could see in the few years I’ve used it in class (in many situations). FakeItEasy and NSubstitute (and also Typemock) take great care in giving lots of information in clear , readable error messages. 

 

  • The future is less confusing. FakeItEasy and NSubstitute are free of “mock” and “stub” in the API. theAPIs of current isolation frameworks abuse and overuse the word ‘Mock” until its meaningless. It should be simple to tell something is a mock - if you verify against it. The API just gets in the way, and confuses newbies, in Moq (everything is a mock? hardly. But everything is a ‘Mock<T>’..!)

 

  • The future is about testing just one thing. FakeItEasy and NSubstitue by default verify a single call, not all of them together. Moq has APIs specifically for testing multiple verifications, which can lead tomaintainable, fragile tests (the past is filled with such tests, because that’s how we used to write tests. We also used to think cigarettes are harmless.). The framework of the future should help prevent over-specification by design.

 

  • The future is robust and future proof. A framework like FakeItEasy (as in Isolator) was built with the understanding that sometimes, in your tests, you don’t care about a *bunch* of methods, or classes, alltogether. you just want them to make “happy noises”. So they give you APIs that allow you to fake things in a cross-cutting faking manner (all methods that return type X are fake, or all static methods on type Y are fake). This is robust because if later we add another method to production code that returns that type, we don’t have to go back to our test and add a line that fake it. It gets included by default. Our tests become more maintainable in the face of production code additions and changes. The frameworks of the past are clueless about such ideas. To me, the idea of faking things with a think brush and declaring “i just don’t care about this whole thing right here, or about anything that looks like X” is the same as the idea of recursive fakes, which was finally introduced in Moq a while ago. It makes our tests smaller, more readable and robust for the future.