TDD is more of a strategy then a certain process or tool. The idea is that testing drives your development — writing tests first, making sure tests pass to indicate development is complete, and continuously testing on each change to make sure no regressions or new bugs slip in.
You can use Espresso, Robotium, or UIAutomator directly for automating the mobile app but testing the UI is inherently slow, can be brittle, and may not be possible (or easy) to write UI (or end-to-end) tests while an app is under development. The UI may not be testable, or back end services may not be complete at early stages.
With test driven development, you want to use your tests to inform what you develop. This informs what you should develop first, and it helps you to write your application in a way that is testable.
If you have some feature that needs tested — for example: delivering different size media (images & video) based on available bandwidth and screen size, testing this with the UI seems to make sense, since it is a UI feature.
But try writing your test the way you want it to look, not the way it actually behaves in the app. Start with your assertion:
assertThat(imageWidth).isEqualTo(deviceScreenWidth);
Now we try to satisfy that
First we need to get our values. Where does deviceScreenWidth
come from? How do we determine imageWidth
?
imageWidth
is probably sent to the response processor so that when it sends the image URL it resizes the image — or selected the appropriately sized image.
That’s a design decision that’s already being influence by our tests. Maybe we want standard sizes — small, medium, large instead of trying to support every possible pixel width. Maybe isEqualTo
should test within a range instead of just equal.
For deviceScreenWidth
we need some representation of our device that includes it’s screen size. Do we get it from the userAgent or does the device send DisplayMetrics
via an API? Is it passed from a service or a lookup table? Maybe we need a test of the function that passes a device identifier from the userAgent and calculates based on known values.
Now we know what code to write — and another test to write.
This can be a bit of a rabbit hole, but we don’t have to tackle everything at once.
In our unit test we just need to have an imageWidth and a deviceScreenWidth. We can make a note of what functions and parameters are needed to get this information, but for now we can just implement the functions immediately needed — and even make our first test pass by having those functions return hard coded values.
A nice simple test might look like this:
public void testImageCalculator() { device = new DeviceMetaData(SAMSUNG_GALAXY_S6); deviceScreenWidth = device.getDisplayMetrics(device).screen.width; imageWidth = getImageSizeForDevice(deviceScreenWidth); assertThat(imageWidth).isBetween(deviceScreenWidth, mediumDeviceMaxWidth); }
Now we know what we need to develop next — the functions that make this test pass. A DeviceMetaData container class, something that gets display metrics for the device, and what we really care about (at this time) — the getImageSizeForDevice()
function.
NOTE: This was originally an answer to a question on Quora