When I was first learning TDD, I’d try to get to the First Step (a failing test) by writing a fully-formed test. But it often took a lot fiddling to get that test to run and fail. Sometimes this was because the production code took several steps to set up. Sometimes it was because the test code wasn’t right.
One of the tricky parts of TDD is that we’re creating two streams of code in parallel: the test code, and the production code. Two things changing at the same time… that’s a hard thing to keep in your head!
A paper published in 2013 about Test-Driven Development included the following diagram. Unfortunately, it gets some things wrong:
A tweet from Nat Pryce sparked discussion:
Grumpy request to academics: if you're going to publish ideas about how to improve TDD, get the original process right! pic.twitter.com/FaSU8CF6ol
— Nat Pryce (@natpryce) September 7, 2017
First, let me say I’m happy to see more studies on TDD. The thrust of this particular study is that TDD can be soft on negative tests. That is, maybe the code works for good data, but it’ll break on bad data.
TDD is a development discipline, so I’m all for learning more from traditional testing disciplines. I certainly don’t want to discourage folks from doing studies and writing papers.
But. Let’s first make sure we’re doing proper TDD, shall we? Otherwise any studies, especially studies about efficacy, may be flawed.
How can we use Test-Driven Development for JSON parsing? Most developers are concerned with ways to implement the production code. There are various approaches, various libraries… But what about the unit test side of things?
If we write effective unit tests, the design can appear incrementally. And with a strong suite of tests, you’re free to change the implementation — even radically. When the results are guaranteed by tests, whatever approach you take or library you use becomes an implementation detail!
Last time, we looked at design principles, such as sticking to the Single Responsibility Principle and returning a Response Model. This time, let’s look at:
When I began my TDD Sample App, my hope was that it would help us explore a number of topics around TDD and Clean Code.
On one hand, the app itself has barely progressed. However, the blog posts cover a surprising variety of topics.
There’s been a growing debate about static languages vs. dynamic languages. For me, it started with Robert Martin’s Type Wars, but it has expanded into many circles. Writing my own reaction helped me discover that I was unfairly judging Swift based on C++.
In the midst of the debate, another interesting article popped up: Eric Elliot’s The Shocking Secret About Static Types. It points to a couple of studies. One study concludes that there is a lack of evidence that static typing reduces defect density. The other study concludes, “There is a small but significant relationship between language class and defects.”
Check out Eric’s fascinating conclusion:
We’ve come full circle: a discussion about static types has again brought us back to TDD. Why?
My TDD has improved since I first started in 2001. But even today, I make mistakes. The trick is to learn to recognize TDD mistakes. Then, learn to “listen” to them: what is it trying to tell me about the design?
Follow along as I recount the latest steps in Marvel Browser, the iOS TDD sample app. Can you spot the errors before I point them out?
Let’s look at how a change to unit testing empowers TDD.
I’ve given you 3 Reasons Why It’s Important to Refactor Tests. But what’s actually involved in refactoring tests?
Disclosure: The book links below are affiliate links. If you buy anything, I earn a commission, at no extra cost to you.
The definitive book on this topic is xUnit Test Patterns: Refactoring Test Code by Gerard Meszaros. It’s a big book, full of patterns and smells. But there are 3 simple steps I take most often.
This is a five-minute screencast where I’m refactoring tests in my iOS TDD sample app using those 3 steps:
You may have seen the 3 steps of “the TDD waltz”: Fail, Pass, Refactor. There are many ways to do it wrong! Two common mistakes are:
So let me give you 3 reasons why it’s important to refactor tests.
Can you TDD networking requests? Sure! It’s just a matter of using Dependency Injection (DI).
But first, a quick recap. Remember this design?
We want a Service class. Now when I began using this style, I made a mistake: I created a single Service class to house an entire API. This violates the Single Responsibility Principle.
The Marvel Browser may end up supporting only one API call. But I’m afraid naming it MarvelService would lead people down the wrong road. We are fetching comic book characters. So let’s use a narrower name: FetchCharactersMarvelService.
Remember: Smaller, focused classes are easier to manage than larger, godlike ones.
Let’s TDD it!