Android networking doesn’t sound very radical nowadays. Actually, it’s hard to find apps that don’t have some sort of network dependency. Some of them won’t even start without a stable network. Others may just degrade gracefully to a limited set of features.
Even though networking is such a fundamental part of an app it’s not the easiest part to write. I would even dare to claim it’s one of the trickiest features. Not only due to implementation details, but rather how it affects several other activities around your app development.
Android networking during early developent
Every now and then you’ll come up with the coolest idea ever. Naturally it just needs that backend API support that doesn’t exist yet. You can, of course, start writing backend support for it but you’re then occupied by another great undertaking. You’re not working on your mind-blowing Android app, and most likely won’t be for quite some time.
Android networking while testing
There are even more tricky scenarios to Android networking. Testing can easily get tricky in itself, even more so when adding networking to it. Suppose you already have a solid code base. The app does what it’s designed for but it’s lacking proper testing on some areas.
You can test the network layer by setting up a dedicated test server. This is quite complicated and adds a certain amount of “noise” to your test reports, caused by timeouts and server downtime. You can alternatively start mocking your code. There are several mocking frameworks aiding you in this, but then you’ll also introduce an observer effect and can’t be sure you’re delivering what you’re testing.
Mock the Internet without refactoring your app
Some time ago I started to play with the idea of mocking the Internet instead of the app. How cool wouldn’t that be? I talked to a colleague of mine and he made a quick spike. The technical implementation involved a minimal web server (NanoHTTPD) running in the app context. The minimal web server then hijacked all network requests made by the app and responded with “mocked Internet” content.
All this without changing a single line of actual app code.
In the simplest possible example code it would translate to a custom Android Application
object doing something like:
public class CustomApplication extends Application { private static final HashMap<String, String> CONTENT = new HashMap<>(); private NanoHTTPD localServer; @Override public void onCreate() { super.onCreate(); // ... a lot of mapping, populating the CONTENT hash map // even more // and then some more... localServer = new NanoHTTPD("localhost", 8080) { @Override public Response serve(IHTTPSession session) { String body = CONTENT.get(session.getUri()); return body != null ? newFixedLengthResponse(Status.OK, "text/plain", body) : super.serve(session); } }; } }
The idea is ridiculously simple, as is the implementation. It saves me tons of time I no longer have to spend on hacking my app. Time I instead can spend on writing awesome features. As a bonus I kind of know what I’m testing and that I’m shipping what I’m testing.
Productified
As the idea evolved, some learnings quickly came to mind. One was realizing that organizing the mocked responses (the CONTENT
hash map in the example above) could be somewhat challenging. If not careful, the saved time could easily be re-invested in setting up the request/response map instead.
One idea to counter fight this new time consuming task was to reuse the exported JSON requests from Postman. This way one could very quickly produce the mocked Internet while testing the backend anyway.
This and many more features are collected in an open source project: Atlantis. In summary, it addresses the less obvious challenges of Android networking. It will also save you even more time (compared to the above example), as it requires even less code to be written. In practice you only need to add a dependency in your Gradle file and start using it:
The gradle stuff:
... dependencies { compile 'com.echsylon.atlantis:atlantis:1.3.0' }
…and the corresponding Java stuff:
public class CustomApplication extends Application { private Atlantis localServer; @Override public void onCreate() { super.onCreate(); localServer = Atlantis.start(this, "postman-output.json", null, null); } }
It’s cool and there is much more to it. Check it out!
Cool, too bad Atlantis cannot be used with non-Android apps ;).
Yes, but you know, secondary platforms are not prioritized at the moment ;-)
I’d also recommend using MockWebServer (https://github.com/square/okhttp/tree/master/mockwebserver) which is incredibly simple yet powerful for Android testing.
This is great! I didn’t know about it. Thanks for the tip!
What do you think of using a remote mock server? No need to write any code – just plug in a url
I am using https://www.amock.io/
Yes, a remote mock server would definitely work too, at least in the early development use case. I haven’t used the particular service you suggest, but at a quick glance it seems to offer a decent subset of what Atlantis offers.
When it comes to automated testing, though, I would discourage using remote (mock) servers as that is exactly what we want to get away from. In automated testing the predictability of the content (knowing exactly *what* is returned) is only half the victory. You still have no guarantees that the content will ever even show up when served from a remote machine.
For testing purposes I would suggest using something that’s running on the same device or emulator you’re performing your tests on. MockWebServer from the Square team (mentioned in a comment above) or Atlantis both serve this purpose better in my opinion.
Suppose I don’t want to create an ApplicationContext just for the purpose of NanoHttpd? Can I start/stop nanohttpd in my unit tests – @Before and @After methods?
Yes, you could start/stop NanoHTTPD in your unit tests as you describe. Keep in mind though that @Before and @After methods will be run before and after *each* test method.
Atlantis has since this post was written moved away from NanoHTTPD though, and is now relying on its own custom server implementation. The new implementation is heavily inspired by MockWebServer, mentioned by Einar in a previous comment. If Atlantis isn’t what one’s looking for I would still recommend to at least have a look at MockWebServer too before deciding to go with any option. I think it’s more suitable for the Android platform than NanoHTTPD and offers way more test related features too.