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!
iPhreaks is a terrific podcast done as a panel discussion. The panel often brings strong experience from other platforms. (In fact, iPhreaks is the iOS cousin to the Ruby Rogues panel.) They already discussed TDD in episode 95. Following up on that, I’m honored that they invited me as their guest to talk more about TDD and Testing in episode 116.
We’ve TDD’d a class that should handle authentication to the Marvel API. It looks good in theory. But how do we know if it really works?
In addition to TDD-ing part of a system, it’s important to get feedback about the system as a whole. So before we go on to write code to request Marvel comic book characters by name, let’s make sure the authentication class works at all.
We’ll do that with an acceptance test.
If I’d been a little more on my game, we could have written the failing acceptance test before beginning our TDD. The acceptance test would drive the TDD from the outside-in. Once the acceptance test passed, we’d know the code was functional. That top-down approach is called Acceptance Test-Driven Development, or ATDD.
But I ended up doing a bottom-up approach. So let’s add an acceptance test now.[This post is part of the series TDD Sample App: The Complete Collection …So Far]
If you don’t know what some code should do, you can’t TDD it. A spike solution (a throwaway experiment) gives enough information to begin the TDD process. But now we’re faced with design decisions: What methods do we want? How should they be organized? How should they be accessed?
With Test-Driven Development, the surprising answer is: it doesn’t matter that much, because it’s going to change anyway.
When I began playing electric bass for high school jazz band, I was often uncertain of the right notes to play. Rather than play a wrong note, I opted to stay silent. The band director finally got frustrated and yelled at me: “I don’t care what you play… just play something!” I learned that the bassist’s role is to establish a good rhythm. A wrong note on the beat is better than no note, because it keeps the rhythm moving.
People beginning Test-Driven Development sometimes freeze up, not wanting to play a “wrong note.” But the purpose of TDD — to get rapid feedback on your code — won’t happen if you stare and think too long. The way to break “analysis paralysis” is to move ahead with a failing test, even if you’re not certain it’s the right one.
In this post, look over my shoulder as I try to apply this TDD mindset to write code that authorizes requests to the Marvel Comics API. Let’s see if any TDD techniques emerge.[This post is part of the series TDD Sample App: The Complete Collection …So Far]
Using a hammer to drive in a screw. I mean, it works, kind of. But if you use a tool in a way other than its intended purpose, you’ll be missing its most important benefits. It’s kind of like that with Test-Driven Development.
Is TDD about preventing bugs? That’s more of a side effect than a direct goal.
Is it about making a test suite? Well, kind of. But… no. Not really.
What is the test suite for? Until you know the intended purpose of Test-Driven Development, you may apply it incorrectly. TDD may seem like wasted work. And without some guiding principles, you won’t know how to optimize your TDD to get the most out of it.
So let me just lay this card on the table: TDD is about feedback. Fast feedback.
Let’s look at how it works in the three steps of the “TDD Waltz”:
It’s one thing to say, “Do test driven development.” But practicing TDD requires a set of tricks — you need techniques to enable test driven development in your particular environment. It’s these techniques which I hope to pass on to you through a case study of building an iOS TDD sample app.
I’ve accumulated a treasure chest of TDD ideas over the years. These ideas are often not my own, but are other people’s ideas which I collect and curate. Some are about object-oriented design. Some are about working in Xcode and Objective-C. And some are particular to iOS development. I’ve collected many, and continue to gather new ones.
I’m building this TDD sample app so that you and I can browse through this treasure chest together. You may have tried test driven development and given up on it. Or maybe you’re still trying, but finding it frustratingly slow. The ideas we will explore together will help you break through to make headway in your TDD journey, so that you can experience the freedom and ease that comes from automated testing and clean code.
The results of my reader survey are in. The #1 request? Case studies of unit testing, with more complex examples. And that got me thinking about the next major direction to take this blog.
When I was first learning Test-Driven Development, I didn’t really have any examples to look at. All I had were descriptions of TDD. I stubbornly believed that these descriptions showed a more effective way of programming, so I fought my way there through the School of Hard Knocks.
But you shouldn’t have to do the same.
Remember my iOS Model-View-Controller TDD screencast? Eric Baker took it a few extra steps with his own follow-up screencast, demonstrating:
There’s a lot of interesting stuff here. But I also want to acknowledge that this screencast changed my mind about dot notation. Yes, really!
What are your thoughts about ReactiveCocoa, Kiwi, or AppCode? Leave a comment below.
The UIViewController TDD screencast ended with all the code in the view controller. Unfortunately, this is where many iOS programmers leave things! Let’s TDD our way to something better…
In part 2, we pick up from there and TDD to extract a model class, which the controller observes. You’ll see it evolve into true Model-View-Controller, driven by unit tests.
In particular, you’ll see how to TDD:
Is TDD worth the extra effort? I got a reaction from one person who tried applying my tips.
Andy Dwelly began applying my TDD screencasts to his iOS coding. Here’s what he writes in Some notes on Test-Driven Development:
At first progress was almost painfully slow.
Yup. It seems like there’s a lot to learn. The real barrier, I think, is that there is a lot to unlearn. When you first start applying Test-Driven Development to real your code, your productivity will take a hit. This is totally normal. But if you’re willing to press through the learning curve, your productivity will increase again — in ways you haven’t experienced before…