I very much agree about the tradeoffs.? I disagree about attributing all the tradeoffs to mocks.? Sometimes mocks are the most expedient way to purely unit test an object in isolation from the objects it calls.
On Tue, Sep 1, 2020 at 8:37 AM <rold9888@...> wrote:
So the biggest difference between the two schools of TDD I mentioned is in their use of mock objects, but there's broad agreement that mocks act as an impediment to some refactorings. People who use mocks extensively do so because they think the trade offs are worth that particular price. Beck wrote the foreword to the book "Growing Object-Oriented Software Guided by Tests" which is the canonical reference for London-school TDD, and was still very complimentary about the book whilst acknowledging that it isn't how he personally practices TDD. To be clear, I don't disagree that structure-insensitivity of tests is a highly desirable property, just with the claim that anyone who doesn't exclusively test an application from the perspective of an end user "doesn't understand" TDD.?
Let's now forget completely about the London-school approach. The section of 'TDD by Example' that you quote is exactly the same one that I referred to before making my previous post, entitled 'Can you drive development with application-level tests?', and it answers that question (to my reading) in the negative. I quote:
Another aspect of [Application test-driven development] is the length of the cycle between test and feedback. If a customer wrote a test and ten days later it finally worked, you would be staring at a red bar most of the time. I think I would still want to do programmer-level TDD, so that
?I got immediate green bars
?I simplified the internal design
I take this section- including the excerpt you quoted- to mean that Beck doesn't have a problem calling a test a unit test if (for example) it tests say three classes working together (whereas a purist might insist on isolating dependencies from an object with test doubles to call it a true unit test). However, this paragraph seems unambiguous in saying that he would write tests at some more granular level than the whole application, which can reasonably be described as 'unit tests'.?
As soon as you write such a test, you expose yourself to the possibility that a refactoring can break that test. As a trivial but concrete example, say you're working on a web app backend with an MVC structure. Your controller handles anything to do with the web layer, including params and rendering a response, but delegates all business logic to SomeClass#some_instance_method.
A 'unit test' of SomeClass#some_instance_method might still be fairly structure insensitive (if the method involves any dependencies, private methods of SomeClass, whatever). But that unit test cares, at the very least, about
The class name SomeClass
The method name some_instance_method
the method signature.
And likely also how to instantiate an instance of the class or set dependencies, unless you're using some sort of factory or an IoC container like Java Spring. Changing any of these things, together with how they are invoked in the controller action, is a refactoring that the user does not care about, but will force you to make the corresponding change in your test.?
There's a tradeoff. Testing smaller units of functionality makes your tests faster to run, easier to write, likely easier to read, more focussed as bug detectors, and helps you manage the internal structure of your code. Your tests being sensitive to things the user doesn't care about is the price you pay for these benefits. Different people value these costs and benefits differently, to the extent that the Chicago and London schools can be recognised as distinct approaches, but even within each school people make their own choices about this compromise (and others) on a smaller scale every time they write a test IMHO.