I’ve been looking for language to help articulate the difference between two styles of unit testing, and really like how Martin describes it in Mocks Aren’t Stubs.

Mocks use behaviour verification.
Classical uses state verification.

 

Classicist Mockist
Like working with real objects Prefer working with fake objects
State verification Behavior verification
Use mocks to test collaborations Use mocks all the time
Will hard code collaboration Will mock collaborations
TDD from middle out TDD from the outside in
Use ObjectMothers/Factories for test setup Will mock only what they need for test collaboration
Test tend to be more coarse grained – approaching more integration style tests Tests tend to be very fine grained – may miss integrations
Classists don’t couple tests to implementation Mockists do
Classists don’t like thinking about implementation when writing tests Mockists do
Don’t mind creating query methods to support testing Mockists typically don’t have to
Classists style can encourage Asking Not Telling design Mockists style encourages Tell Don’t Ask

Classical vs Mocking

I generally prefer the classical style to the mocking mostly because I don’t like thinking about implementation when writing a test.

I do however like having the mocking option in my back pocket, for those cases when a system is difficult to test, an object has a nasty setup, or I am refactoring legacy code.

The other piece of advice I recommend (my ex colleague Jonas Claesson turned me onto this) is to keep your calculations separate from your orchestrations.

If you can do this you get the best of both worlds. Calculations can be classically testing. Thin orchestrations mocked. Should keep both set easy to read, and easy to setup.

Here are some more summary notes from Martins article.

Article summary

Regular tests

  • state verification

Mock tests

  • behavior verification

Classical and Mockist Testing

  • Classical style uses real objects
  • Mocking style is to do everything with mocks
  • Classicists will use mocks for creating doubles

Choosing between the differences

  • If collaboration of objects is easy – classic is obvious choice
  • If collaboration between objects is awkward – mock
  • No big choice to be made here
  • Where things get more interesting is when we talk TDD

Driving TDD

  • Mockist will TDD there systems from the outside in
  • They will start with the GUI, describe their collaborations, and progressively marching deeper and deeper into the stack one layer at a time
  • Classical TDD doesn’t offer that kind of guidance
  • Whenever a classist requires something from a collaborator they simply hard code it
  • But classists take a slightly different approach – middle out
  • Here a classist will create an object for whatever domain they need and once they are working then you layer on the UI
  • Doing this you may never need to fake anything
  • Focuses the attention on the domain model, which helps keep the logic from leaking into the UI

Fixture Setup

  • Classic TDD needs to create SUT with all it’s collaborators
  • Mockists need only create SUT and mocks for immediate neighbours
  • Classics will do this using ObjectMothers – reuse whole objects
  • Mockists will say this is more work
  • Classists will say we do this once and reuse – you setup every time

Test Isolation

  • If you introduce a bug mocking, only those tests whose SUT contains the bug will fail
  • In classic, any tests of client objects also fail – ripple effect throughout system
  • Mocksts will say make finding bug harder to find
  • Classists say its usually pretty obvious – little bit more noise

Granularity

  • Classic tests can be more coarse grained than mockists as they test overall interaction of objects
  • In essence classic xunit tests are not just unit tests, but also mini-integration tests
  • Classists like this
  • Mocksts lose that quality – also run the risk that the mocks are incorrect masking inherent errors
  • Which ever way you go you need both – coarse and fine grained

Coupling Tests to implementation

  • Mockists couple their tests to implementation
  • Classiss don’t care about implementation – only the final state – not how it was arrived
  • With mock testing, writing the test makes you think about the implementation behavior
  • Mocksist like this – classists dont
  • Coupling implementation also interfere with refactoring, since implementaiton changes are more likely to break tests than classic testing

Design style

  • Classist are more comfortable creating query methods to support testing
  • Mockists don’t have to do that as much
  • Mocking also encourages Tell Don’t Ask
  • Classis can encourage Asking Not Telling – though in practice this is easily hadnleld
  • Mocking can also result in more classes (interfaces in various languages)
  • May not be as true now, but i remember many more interfaces and classes being ccreated than was necseary when mocking
  • Also DHH dislikes the designs mocking sometimes creates – mockists like it

Classic or mockist?

  • I have never seen a reason to go all mock
  • Mockists focus solely on implementation details of the SUT – never felt nature to me

Jonas

  • Don’t combine logic with orchestrations
  • Logic classis – classic mock
  • Orchestrations – simple as possible, no calcs, mockist

Links that help

http://www.martinfowler.com/articles/mocksArentStubs.html

http://googletesting.blogspot.se/2015/01/testing-on-toilet-change-detector-tests.html

Advertisements