Re: Three Law of TDD - to strictly follow, or not?

"Wouter Lagerweij [email protected] [testdrivendevelopment]" <[email protected]> Thu, 28 Aug 2014 17:04:56 +0200
Newsgroups gmane.comp.programming.test-driven-development
Message-ID <CABJ7RBx7ObHo2UJ1VPdp+T4aRQ8LQZEUsxwdwXHvF=OTrp_jqg@mail.gmail.com>
Hi Kaleb,


As others have said: Change gear depending on your experience wit TDD and
comfort in the situation.


There's a another point to be made though. Ron and Chet emphasized in their
CSD training that TDD has two 'modes': design and implementation. When you
write a new test, it usually introduces some sort of new concept in the
system. You can write more than one line, even if the first line doesn't
compile, if that helps you see what the interface/design should look like.
When you have something you like, you make sure it compiles, but fails.
Then you start with the implementation mode, and make it work.


If there are more than one or two new concepts introduced in one test, I'd
wonder if the test is maybe a little to broad in scope, and I should take a
smaller steps.


Wouter




On Tue, Aug 26, 2014 at 5:48 PM, Kaleb Pederson [email protected]
[testdrivendevelopment] <[email protected]> wrote:


>
>
> Over the last three years I've been doing training on and advocating TDD
> where I work and a number of people have been striving to learn and use TDD
> in their daily development :).
>
> --- An experience with coworker 1 ---
>
> One of these coworkers recently published a 6-part series on TDD that
> starts off assuming no prior experience with TDD (
> https://www.simple-talk.com/dotnet/.net-framework/a-tdd-journey-1-trials-and-tribulations/
> ).
>
> In part two, having recently introduced the three laws of TDD, he wrote
> the following (
> https://www.simple-talk.com/dotnet/.net-framework/a-tdd-journey-2--naming-tests-mocking-frameworks-dependency-injection/
> ):
>
> [Test]
>
> public void Execute_delegates_to_IWidgetLoader_to_load_widget_details()
>
> {
>
>     var activator = new WidgetActivator();
>
>  }
>
>
> At this point the test fails because WidgetActivator doesn't exist. He
> then proceeds to introduce a dependency and a constructor parameter before
> making the test pass:
>
> var mockWidgetLoader = new Mock<IWidgetLoader>();
> var activator = new WidgetActivator(mockWidgetLoader.Object);
>
> When a commenter pointed out that he was violating the three laws of TDD
> of he commented:
>
> "When adding a new test, you do not stop as soon as it turns red; rather
> you stop when the test is completely written. Then you labor to make that
> test turn green by modfiying [sic] the class-under-test. Think about it
> this way: if you write a partial test then make it go green, you now have a
> passing test *that is wrong*. A test should be green if and only if it is
> valid."
>
> I disagree with the comment because it allows multiple unnecessary lines
> of code to be written and doesn't provide a progression that guarantees
> that all production code is effectively "tested"/covered. It also makes it
> harder to get feedback from the test about the design of the system. Sure,
> the developer might tweak the test code to improve the API but at that
> point the API design isn't supported by a working implementation so it's
> not necessarily going to reveal design defects as quickly.
>
> Another person pointed out that "an incomplete but green test is at best
> misleading and at worst wrong: if a test is green it should be a valid
> test, and a partial or incomplete test is not valid."
>
> --- An experience with coworker 2 ---
>
> Coworker 2 recently came to me with some questions. He described his
> process wherein he would:
>
> * Create an empty test
> * Add a variable assignment: var instance = new MyClass();
> * Introduce the class
> * Add dependency1 to that class: var instance = new MyClass(dep1);
> * Add that dependency as a constructor parameter
> * Add dependency2 to that class: var instance = new MyClass(dep1, dep2);
> * Call the method to be under test: var result = instance.Execute();
> * Define the method under test
> * Add a parameter to the callsite of the method under test: var result =
> instance.Execute(param1);
> * Add the new parameter to the implementation of the method under test
> * Add another parameter to the callsite of the method under test: var
> result = instance.Execute(p1, p2);

> * ...
>
> The story, in short, is that no matter what he was doing extremely small
> steps -- steps that felt unnaturally small to me. Ultimately he had a
> number of problems which seemed to be because he wasn't letting the tests
> guide the implementation but he felt the implementation went really slowly
> because after writing a fair amount of code and he'd have to come back and
> modify many of his tests when a new parameter to a method needed to be
> added.
>
> I introduced him to ATDD/double-loop TDD in hopes that it'd help him work
> in vertical slices, let the system evolve, and help him discover the
> required parameters/dependencies early in the process.

>
> --- Questions ---
>
> Both of the above experiences and questions go back to understanding the
> three laws of TDD and step size. As I'm entirely self taught, I'd like to
> know your thoughts.
>
> Do you strictly follow the three laws of TDD as literally written?
> What step size do you typically have when going back and forth between
> tests and code?
> How do you decide the appropriate step size?
> When writing a test, do you define a method or constructor with all its
> expected parameters?
> Do you consider, "an incomplete but green test is at best misleading and
> at worst wrong"?
>
> Thank you for the feedback.
>
> --Kaleb
>
>  
>






-- 
Wouter Lagerweij          | [email protected]
http://www.lagerweij.com  | @wouterla <http://twitter.com/#!/wouterla>
linkedin.com/in/lagerweij | +31(0)6 28553506