Notes from Jonah Williams

Writing Reliable iOS Tests

By on in Development

Tests help me write better apps. Writing tests informs my interface designs, expresses some of my intentions, and guards against regressions. As applications grow so do the number of tests I’m running as a regular part of my development workflow. If I’m not careful those growing test suites can slow down, become inconsistent, and eventually lose the trust of the development team. Fortunately, test driving software design is not a new idea and we can look to other languages and frameworks with good testing practices for inspiration on how to avoid pitfalls we encounter when writing tests.

I ran into a couple of cases on recent projects where I wrote unreliable iOS XCTests. Let’s take a look at what went wrong, what a better test might look like, and what tools we, as iOS developers, might be missing.

Continue reading …

Minimizing downtime when deploying to Heroku

By on in Development

Heroku has become our default hosting platform for most new projects. It’s simple to deploy new rails apps, encourages some good conventions, is able to provide the services most applications need, and can offers a simple scaling solution which can usually handle whatever growth new products are able to produce.

We also like automated and ideally continuous deployments which allow us to push changes live many times per day as we build out a new product. Since we hope any new product is going to have at least a few users it would be nice to avoid or at least minimize taking the site down during those deploys.

Continue reading …

Writing Deterministic & Performant Specs with Capybara

By on in Development

Acceptance tests are a great tool for guiding [outside in testing] and defining application behavior. Unfortunately they are also notoriously slow and often brittle. At Carbon Five we usually use Capybara to drive our acceptance tests (either directly in RSpec feature specs or within Cucumber steps) so let’s explore some ways we might accidentally write bad tests and how to avoid them.

If we are using Capybara’s RackTest driver things are fairly simple. The driver doesn’t support JavaScript so we have a single Ruby process running our tests and performing synchronous requests against our application. Unfortuanetly this is usually insufficient to exercise client side application behavior which requires running JavaScript. (We’ll leave discussion of if it is appropriate to exercise both client and server side behavior in a single test for another post.) Instead of RackTest we usually use the Poltergeist driver which provides a headless WebKit browser capable of executing JavaScript served by our app.

For these examples we use RSpec feature specs which use the Capybara DSL directly. In large apps we might find the same behaviors wrapped in Cucumber step definitions or inside custom RSpec matchers. Those may make if more difficult to spot poorly performing assertions.

Continue reading …

Readme Essentials

By on in Process

On recent projects I’ve been trying to practice a little bit of readme driven development and trying to demand that the project maintain a useful readme. Theoretically the contents of the readme are things the entire development team is familiar with. Capturing them in a readme has still proven to be a useful exercise which adds clarity to the project’s structure, reveals tricks known by only some developers, and has been a significant time saver when bringing new developers onto the project.

Each project has its own needs but I have found that they all benefit from instructions which allow other developers to get up to speed quickly. When I join a project as a developer or consider using a shared library, I should be able to answer at a glace:

  • What does this project do?
  • How can I see it work?
  • How do I run tests?
  • How do I install/deploy/release the project?
  • How should I submit contributions or report bugs?
  • How do I know what needs to be done?
  • What license is this offered under?

With those questions in mind I’ve started using the following as a template for my projects’ readme files:

Continue reading …

iOS Integration Tests with Kiwi

By on in Development

I have been using Kiwi to run my iOS projects’ tests. Kiwi works great for defining BDD style unit tests which express the sort of nested assertions I like to write.

Unit tests should test code in isolation so that they remain small, fast, and stable. So my unit tests mock or stub any network calls or calls to other components, assert that those calls were made correctly, and invoke callbacks where necessary.

I recently wanted to add a set of integration tests which would verify that the app I was building could successfully interact with a remote API. These are certainly not unit tests; they are comparatively slow to run, they are fragile as they depend on a functing remote server configued in a known configuration, and they excercise several application components working together. They are also a great way to verify that the API version which the app communicates with still works as expected. Without such tests changes to the client or server could brake behaviors we rely on.

Continue reading …

Fixture data for iOS tests

By on in Development

I have talked about running xcode units tests from the command line before. When I’m running tests I often want to load some sort of test fixture data for use in my tests. For example: I might want to keep a file of recorded API responses so that I can stub out network calls.

In an application I would normally load a local resource using NSBundle:

NSBundle *bundle = [NSBundle mainBundle];
NSDictionary *data = [NSDictionary dictionaryWithContentsOfURL:[bundle URLForResource:@"data" withExtension:@"plist"]];

However this won’t work for resources included only in a logic test target. Instead I have to find the test class’ bundle:

- (void)testLoadingResources
    NSBundle *bundle = [NSBundle bundleForClass:[self class]];
    NSDictionary *data = [NSDictionary dictionaryWithContentsOfURL:[bundle URLForResource:@"test_data" withExtension:@"plist"]];

Breaking into the debugger while running tests we can see that multiple bundles are available when running logic tests (when a TEST_HOST has not been set):

(lldb) po [NSBundle allBundles]
(id) $4 = 0x01939c90 <__NSArrayI 0x1939c90>(
NSBundle </Applications/> (loaded),
NSBundle </Users/Jonah/Library/Developer/Xcode/DerivedData/demo-cmievackjxrgicduqyniuhyntvje/Build/Products/Debug-iphonesimulator/demoTests.octest> (loaded)

While application tests only have a single bundle:

(lldb) po [NSBundle allBundles]
(id) $3 = 0x06a527f0 <__NSArrayI 0x6a527f0>(
NSBundle </Users/Jonah/Library/Application Support/iPhone Simulator/5.1/Applications/E4292AB1-4F69-4D7D-AF96-C9FA09B34F17/> (loaded)

[NSBundle bundleForClass:[self class]] will return the appropriate bundle in either case.

Customizing the iOS keyboard

By on in Development

Our applications need input and the default iOS keyboards are often not optimally suited to providing the sort of data we want. When we find that we really wish the keyboard had some extra controls or want to help our users enter a specific set of symbols it is time to customize our apps’ keyboards.

Continue reading …

Lightning talks at Carbon Five, 9/28/2011

By on in Everything Else

Carbon Five had a set of lightning talks over lunch recently. Giving our designers and developers a chance to share recent experiences and side projects.

A debate over the relative performance of different languages at our last hack night called for a measurable comparison. Mike demonstrated the resulting head to head to head speed test serving “Hello World” from Ruby, Node.js, and Go.

Dave gave us a summary of Agile UX presentations from the Balanced Team Conference

Jonah has been working on a tool to parse and manipulate Xcode project files. Using a parsing expression grammar defined in treetop to parse the file and generate a tree of ruby objects which could be manipulated to resolve merges, organize resources, or manage dependencies.

Our resident node.js expert Ben explained how he has been using jasmine and zombie to practice BDD while working with node.

Rudy has been working on iOS apps and gave us a demonstration of how to use objective-c metaprogramming to monkey-patch new behaviors and state onto existing framework classes.

We will be playing with these and other ideas at our next Hack Night on Wednesday October 5th if you would like to see more.

Designing mobile APIs – error handling

By on in Development

While designing an api I need to provide reliable error responses to both protocol and application level errors. Here I’ll consider any error response generated outside our application stack to be a protocol error while those errors returned from my application’s codebase are classified as application level errors. On a recent project I started to conflate these two categories which would have made the client implementation unnecessarily difficult if my pair had not intervened.
Continue reading …