We’re pair programming, with you driving. You’re using Xcode.
I don’t say anything because I don’t want to offend you. But you’re having to do So. Much. Typing.
They say typing isn’t the slowest part of programming. But as I sit with you, I wonder… Why isn’t the code automatically appearing? We’re on a computer working in a computer language, so why doesn’t the IDE understand your intent? Why do you have to make the same changes in so many places?
Oh yeah. You’re using Xcode.
With AppCode, it feels like code flies from my head to the screen. For me, coding is manipulating ideas rather than characters. I have a coworker who would rather pair together at my computer, so that I can drive using AppCode.
What does it look like in practice? Let’s continue in my sample TDD project.
You may have thought I’d forgotten my sample TDD project, the Marvel Browser. Sorry, I’ve been busy making big changes to OCHamcrest and to OCMockito. Let’s get back to the example.
We’ve TDD’d code that satisfies Marvel’s authentication scheme. We have an acceptance test showing that it works for a simple query. What’s the next step? Well, we need something to fetch Marvel comic characters. Following Domain-Driven Design, let’s begin creating a Service to talk to the Marvel API.
The first step in TDD is to create a new test. Let’s skip over the steps of adding a new test file, and jump straight into test code.
In the test file, you can type ⌘N and see many code generation options. These include “Test Method” and many other interesting choices. But for tests, I prefer to use my own templates.
So instead, I type ⌘J which is the shortcut for “Insert Live Template.” Live templates are like code snippets, but with more smarts. Here’s what my selection looks like when I type “t” for test:
What you see here are a few built-in defaults, but mostly my custom templates. If you like what you see, get my templates
Selecting “Test case” creates a test with the default name testFoo_ShouldBar. AppCode selected the part after the test prefix, so I can start typing to give it a different name. Hitting Enter accepts the name and moves the cursor into the test body.
Let’s start the “Arrange” section of our test. In the test body, ⌘J again to bring up the templates. The first choice is “Insert alloc and init” so I hit Enter. This fills in
with NSObject selected so that we can replace it. Let’s type the name of our Service: QCOMarvelService.
Hitting Enter accepts the name of the class. AppCode jumps over to select “init” in case we want a different initializer. The default is fine, so let’s hit Enter again. The cursor is now at the end of the expression. A semicolon there makes it a legal statement.
Full stop. That’s enough to be syntactically correct, but fail to compile. According to Uncle Bob’s Three Laws of TDD, we should write only enough of a test to demonstrate a failure. And compiler errors are failures. So now we shift to production code. Let’s put the cursor in QCOMarvelService.
Here comes the magic.
Option-Enter brings up a menu of intentions:
Why yes, I would like to create a new class. I hit Enter, specify the location of the new file, and OK. Done.
AppCode’s claim to fame lies in its automated refactoring. So many choices! Control-T brings up the handy “Refactor This” menu. But in this case, my fingers know the shortcut for Extract Variable is ⌥⌘V. Look at what that does:
Not only does it enter the type, it offers good suggestions for the name! In this case, I’m going to make the name sut for System Under Test. …But quite often, I just select one of the suggested names.
Come on, that’s cool.
Using the acceptance test as a reference, I know we’ll need an NSURLSessionConfiguration. I don’t know if it needs to be a property, or something else. Rather than debating the issue, let’s break “Analysis Paralysis” and start with a property. Remember, “Move ahead with a failing test, even if you’re not certain it’s the right one.”
So the “Act” section of our test will query an as-yet-nonexistent property. This time, instead of extracting it to a variable later, I type out the assignment in full. You’ll soon see why.
Once again, we have a test that is syntactically correct, but fails to compile. That’s TDD Red. To go to TDD Green, we set the cursor in the property reference and Option-Enter:
I select the option to create a new property, hit Enter. A popup appears, allowing me to set the property’s semantics. It’s fine the way it is, so Enter again.
Because I started from a full assignment, AppCode inferred the type of the property. (Otherwise, it will fall back to id.)
Now the “Assert” section. I type the following (and appreciate the improved hints of OCHamcrest 5.0.0). My “Tests” configuration is ready to run, so I Control-R to run all unit tests:
Xcode does a nice job of letting you click the diamond icon next to a test suite or a single test, to run what you selected. But let’s say you want to rerun that test. You have to position the mouse cursor over that little diamond all over again! It’s a slow, click-intensive process.
But AppCode is keyboard-centric. You can set up configurations to run tests in a specified target, class or method. Control-R to run — no mouse movements necessary.
There’s even a “Rerun Failed Tests” button.
We now have a complete failing test. To get it to pass, I’d like to customize the getter method for the property. Control-clicking on the property takes us to its definition. Then I Control-O which is the shortcut for “Override Methods”:
I select the property getter, and OK. Normally, this would generate an empty method for me to fill in.
Hold on to your hats.
Here’s what happened when I generated the getter method:
That’s a lazy property, ready to go, without my typing a thing!
This is not default behavior. It comes from pasting this gist into one of AppCode’s code template settings.
Lazy properties are usually what I want to support property injection. This may prove to be overkill for the NSURLSessionConfiguration. I’ll revisit this later. Right now, my goal is to move ahead quickly.
So for now, my test passes — without typing any code!
That’s an overview of the features I used for this one test. I go into more detail in a screencast, Better TDD: The AppCode Advantage.
Of course, there are more features that I don’t mention even in the screencast. The longer I use AppCode, the more I discover. The boost I get in productivity easily justifies the cost.
What are you waiting for?
What’s one of your favorite AppCode features? Click here to leave a comment.
Jon is a coach and consultant on iOS Clean Code (Test Driven Development, unit testing, refactoring, design). He’s been practicing TDD since 2001. You can learn more about his background, or see what services he can bring to your organization.