The dangers of over mocking
Classicist vs Mockist approach to TDD is a classic and ongoing debate in the software community.
I’ve long been a classicist but I started out my career as a mockist.
Recently I came up against a particularly poignant example of the drawbacks of heavy mocking and wanted to share the experience.
The Mockists solution
1 class ProductControllerTest 2 def test_should_show_price 3 Product.stubs(:find_by_product_code).returns(stub(:price => 12.50)) 4 5 get :show, :product_code => 'IPOD' 6 assert_select '.price', '12.50' 7 end 8 end
In the test above we want to make sure that the controller shows the price on the product page. We don’t want to test ActiveRecord functionality so we stub out find_by_product_code. We implement the controller to use find by product code and our test passes. Great! Well not really.
Six month later another developer is refactoring. Everyone in the whole business refers to product_code as SKU, and all the developers keep getting confused so a rename is in order. One quick migration later, the rename is done and the test suit is running. Sadly our test above won’t fail, even though the column is gone leaving us with a meaningless test and broken code :(
The Classicists solution
1 class ProductControllerTest 2 def test_should_show_price 3 product = Product.create!(:price => 12.50, :product_code => 'IPOD') 4 5 get :show, :product_code => 'IPOD' 6 assert_select '.price', '12.50' 7 end 8 end
Actually creating the object instead of mocks prevents your test being tied to your implementation and in the mockist case above, hiding potential errors.
