Built to Support TDD: 7 Cool AppCode Features

December 8, 2015

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.

1908 advertisement for Remington typewriter

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.

TDD example

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.

1. Hey AppCode: Create a new test

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:

Test templates in AppCode

Click to see larger version

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.

2. Hey AppCode: Create a new class

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

[[NSObject alloc] init]

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:

Option-Enter for AppCode intentions

Click to see larger version

Why yes, I would like to create a new class. I hit Enter, specify the location of the new file, and OK. Done.

3. Hey AppCode: Extract a variable

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:

Extract variable in AppCode

Click to see larger version

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.

4. Hey AppCode: Create a new property

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:

Create new property in AppCode

Click to see larger version

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.

Done. Magic.

Because I started from a full assignment, AppCode inferred the type of the property. (Otherwise, it will fall back to id.)

5. Hey AppCode: Run the tests

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:

Run tests in AppCode

Click to see larger version

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.

6. Hey AppCode: Override a method

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”:

Override method in AppCode

Click to see larger version

I select the property getter, and OK. Normally, this would generate an empty method for me to fill in.

Hold on to your hats.

7. Hey AppCode: Generate a lazy property

Here’s what happened when I generated the getter method:

Generate lazy property in AppCode

Click to see larger version

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!

Scratching the surface

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 Reid

Posts Twitter Facebook Google+

I've been practicing Test Driven Development (TDD) since 2001. Learn more on my About page.

11 responses to Built to Support TDD: 7 Cool AppCode Features

  1. I tried Appcode for a (short) time, and it felt like Appcode is not ready for Swift development yet. Are you still an Obj-C oldschool purist?

    • Yes, for now.
      But lately with every new release, the release notes focus on improvements for Swift. Have you tried the current beta?

      • I’m using AppCode 3.3.3 EAP. It’s very powerful for Objective-C projects, but with Swift, it’s very weak.

        We tried to do TDD with recent Swift project, all powerful features you mentioned above is completely missing :). It takes a lot of times to write tests, then manually create new classes, methods,… 🙁

        • Stanislav Dombrovsky January 25, 2016 at 3:15 am

          Hi, my name is Stanislav Dombrovsky and I’m Product Marketing Manager in JetBrains AppCode team. For now we are working hard on Swift language support tasks that will allow us to implement such “smart” features like code generation for Swift and better support for Swift tests. For the moment you are right – “smart” features for TDD are not ready for Swift yet.

  2. I check in on every new App Code release and its support for Swift improves only glacially. I use App Code for its refactoring abilities, and there are still only a handful of them for Swift (rename, wrap in do-catch). It’s got a long way to go to be relevant again in a Swift world.

  3. Tracy B. Porter January 7, 2016 at 10:42 am

    I am drawn to ANY article that starts “We’re pair programming…..”

    I am a developer in Minneapolis and pair programming gigs are scarce. Is the practice more common on the west coast?

    I am new to iOS development. I wrote my first Swift and Objective C apps last year. I abandoned Swift pretty quickly because the tool support is so poor. That said, Objective C makes java look pretty. Yikes.

    Thank you for the AppCode and Swift updates. I am poised to start my next app and will lean toward Objective C and the strange AppCode/Xcode dance I find myself doing for the UI implementation.

    • Tracy,
      I doubt that pair programming is more common on the west coast. So far, I’ve experienced it as a loose, bottom-up thing: “Can we do this together? It’ll be faster.” I haven’t experienced it as a discipline. I know of only one company that requires it.

      I’ve resisted the Swift bandwagon so far because TOOLS.

      I still dance over to Xcode for Interface Builder, and for the debugger. So, go for it. 🙂

  4. Hi Jon,

    I do completely agree that AppCode is amazing when working with Objective-C!
    For those projects I ended up having the two behemoths running side-by-side (Xcode for Core Data, UI building and testing, as well as publishing to the iTS; AppCode for coding, testing and debugging).

    A few days ago I took AppCode for a spin with a Swift project and was extremely
    disappointed – it felt like using NotePad with a file browser on the side…
    Most of the tools that made me use AppCode for iOS development are pretty much absent. All I can do from my regular workflow, is Run the current test method, Implement a method from a protocol, and override a method from the superclass, and open a recent file. It’s even impossible to extract a variable or a method, or to inline it back.

    I know that the JetBrains team are working very hard, and I’ve watched their other tools develop while using them and reporting bugs along the way, and I remember the times when AppCode didn’t have many advantages over Xcode. I believe that the recent publication of Swift to the public domain will help the JetBrains team to move faster, and I really hope we will be able to use their amazing tools with Swift by the end of this year.

    All the best, and keep up the great work!

    • Stanislav Dombrovsky January 25, 2016 at 3:21 am

      I really hope we will be able to use their amazing tools with Swift by the end of this year

      I hope it will happen earlier – some smart features for Swift are already on the way and planned for 3.4 release