I write automated unit tests for each of the classes inside my apps. This includes iOS apps, which have classes that extend classes defined by the iOS framework. I want these classes to take care of the framework-specific and device-specific details of showing new screens, handling their life cycles, et cetera. For other logic that I write, I like to have my view controllers and other iOS objects delegate that work to injected classes.
I’ll call this post “When and How I Use Robolectric” instead of “When and How to Use Robolectric” because a) I don’t like telling people when and how to do things, and b) I use Robolectric less liberally than most developers who use it.
Robolectric is a fantastic tool for ensuring that stuff in your Android app works properly. The problem, as you may have heard me say before, is that it runs slowly. In particular, FragmentTestUtil’s operations are especially time-expensive. Compounding the issue, Robolectric 3.0 currently has a memory leak that causes the heap to get bigger than it should. You won’t notice it on a smaller app, but when the app grows enough for the test suite to hit 600 or 700 Robolectric-assisted tests, the suite will hang or stop running because it runs out of memory before it completes.
So you only have 600-ish Robolectric bucks in the bank, and you spend one every time you write a test with Robolectric. My team at work, and I at home, have experimented with ways to save our Robolectric bucks. The first (main) trick has been to separate as much logic from the Android framework as possible and test that logic with JUnit. We save our precious Robolectric bucks this way, spending them on just a test or two for the places where the logic gets wired into the Android app.
It’s much easier to write a test-driven application when we can isolate the class under test, so its tests fail as a result of its behavior and not the behavior of its dependencies. Exercising the dependencies in tests—whether they’re collaborating classes or entire frameworks—increases the number of reasons that a test might be failing, which limits how helpful that test can be in diagnosing issues and driving out an implementation.
In Android, there’s an additional concern: exercising the Android framework in tests is slow. So it makes sense to exercise the framework as little as possible in tests. This gets complicated when we consider the way the Android framework is built, though. First of all, it works chiefly by allowing us to subclass Android classes and override life cycle methods. This is not a recipe for easy dependency injection. Furthermore, idiosyncratic implementations of Android sometimes involve obtaining dependencies (like views from the layout) via a method besides injection. (We talk about how to test dependencies in that scenario in this post).
But there’s another catch to decoupling and testing in Android: the launching of some components depends on passing in other components.
I test-drive Android apps with some help from the Robolectric testing framework. I also get some help (usually) from the Dagger dependency injector for employing dependency injection in those apps. I define modules in dagger for injecting classes into objects that depend on them, and I define test modules that inject mock versions of those classes when I write automated tests for the objects that depend on them.
As I learned more of the Robolectric and Dagger syntax over time, I could test-drive Android app features faster and faster. I did have an issue, though; in order to inject dependencies in Android, I needed a context. The Context object in Android provides information about the application environment, and it enables app-specific stuff like launching activities and sending/receiving broadcasts.
Welcome! You’ve landed on the second post in a series of posts designed to be companion reading for Android Programming: The Big Nerd Ranch Guide, 2nd ed.
BNR goes step-by-step through how to make a RecyclerView and all of the component objects that come together to make it work. The RecyclerView differs from the ListView, which is the list creation method that I have used the most in Android, so I was excited to see the RecyclerView in action. That having been said, the explanation in the book spreads out over several pages; I wanted to find something more concise to help me achieve a high-level picture of how everything talks to each other and how I might implement a RecyclerView on my own rather than copying the code verbatim in the book. I found this blog post by Ashraff Hathibelagal, which helped me sketch out a responsibility diagram for RecyclerViews to contrast with a responsibility diagram of its predecessor, the ListView/GridView:
I’ve just finished my second read-through of Test Driven Development by Kent Beck (thank you to Austin at Pivotal for loaning it to me!). Even on the second read, I must liken my experience of reading it to that of watching this lightsaber battle:
It’s fascinating and mesmerizing, and people who clearly know exactly what they are doing make lightspeed decisions back to back to back directly before my eyes. I watch and rewatch with a sense of awe, hoping that I, too, can one day make the split-second design decisions that Beck makes with such ease in both Java and Python. And, like anyone who has attempted to learn to reenact the above lightsaber battle, I found myself often pausing and rereading Beck’s examples in an effort to break them down and understand what, why, and how.
This afternoon at Windy City Rails, Matt Polito of HashRocket gave a talk called “Why Cucumber is Still Relevant.” For those who haven’t used it, Cucumber is a gem used in conjunction with writing tests in a rails application that provides a domain-specific language for describing and documenting what the application is supposed to do.
He brought up this article by Martin Fowler, which poses a question:
Will DSLs allow business people to write software rules without involving programmers?
He ends up answering this in the negative, but instead identifies the value of making software business-readable rather than business-writable.
When Jessica Kerr stepped onto the stage at Windy City Rails, she asked us to rethink our sometimes not-so-positive visceral reaction to testing our code. Maybe what we need isn’t to break up with TDD. Maybe we need to go deeper in and work on the relationship
Jessica’s suggestion for this is to take some wisdom from testing in the functional programming community: to consider including generative testing or property-based testing in our test suite, rather than reaching exclusively for the example-based tests we’ve come to know.
Generators are classes that produce random input data, and in the context of tests we can use them to generate, say, 100 random examples, and run all 100 examples through our tests.
Our tests will then evaluate those examples on properties. WARNING, Object-Oriented programmers: in the context of functional programming from whence these tests come, properties are not fields on a class. Instead, they are assertions: the kinds of things you want to make sure are true in a test. In property-based testing, we test for all these properties for each of our randomly generated examples.
This is different from our current example-based testing, in which we take one explicitly specified example and check that a hard-coded expected value equals the actual value.