Posted on

Android Testing | Local Tests pt 1.1


android local tests

Designed by Freepik

Alright, let’s start our Android testing journey from the ground up with the very basics: local unit tests

Purpose of Local Unit tests

As follows from the introduction – local unit tests don’t have any access to Android framework, you can still import their classes, but they will throw an exception when you’ll try to call any methods. Here’s a text from Google documentation

By default, the Android Plug-in for Gradle executes your local unit tests against a modified version of the android.jar library, which does not contain any actual code. Instead, method calls to Android classes from your unit test throw an exception. This is to make sure you test only your code and do not depend on any particular behavior of the Android platform (that you have not explicitly mocked)

But as mentioned above – you can still mock framework’s methods with libraries like Mockito or even using Robolectric which they say brings you almost to the level of instrumented tests

In this post, we will just what we can achieve with simple tests without any of the libraries above

android local tests

Also from this pyramid, Google suggest having 70% of local unit tests. So since that’s a big chunk of tests – I want to really get deep into those and understand their place in a development cycle. That’s why there’s going to be at least three parts: the current one, Mockito and Robolectric. All with best examples I can find

Setup

There’s no extra setup needed, just by creating a project with Android Studio, you get everything set up for you to write tests. You’ll see a java file created for you already in app/src/test/java/…

Now since this post is going to cover simple local tests, let’s start with examples to get what we can achieve with this kind of tests

Example 1

From Google samples, there was an email verifier test. But I don’t want to repeat that and my first example will be extracting first name from a full name. From what I saw – naming convention for tests goes like this – methodNameThatYouTest_InputIfAnyExists_ExpectedResult

You can simply test every single input/case in just one test method and call it after the method you test, but I believe the way above is more popular and more readable, so let’s use it

Since we’re going to learn a bit about TDD way – first thing you create are tests and then actual implementation

android local tests

Out method will be called extractFirstName, first, of course, we need a stub method


Now we can figure out possible cases. Here’re several test cases I came up with


Now let’s run those tests and here’s the result I got, all failed

android local tests

Finally we can start implementing our method. Since it’s the very fist example I want to go through the whole thought process, step by step. First thing that comes up is to handle null or empty inputs 


Let’s run tests

android local tests

Next, let’s just use a #String.split method


android local tests

Already more tests are passing. You get the point, now just finalize this method to pass all tests


android local tests

I think you get the idea, the same way we’ll create a method for capitalizing first letter of a name if it was lower case

Example 2

Now another pretty common thing I found is parsing JSON response from a server into your POJO. Not the simple one from your backend where all the data has the same names/fields that you use, but the one from other API which maybe has different field names that you want to use and with some deep nesting which you want to flatten out

The first thing comes up to my mind is Google Maps API place endpoint, where you get latitude, longitude of a given city and much more information. It all is very nested. Here’s an example of response from server querying for Dallas


 

Here’s our POJO model


 

You could map every field like in json response from server, but it won’t look clean and since I want to save location to my server as well – that would be redundant data stored on my server.

Now let’s add Gson library to dependencies


 

And stub method

Test Cases

Let’s get to it. 

Read JSON Files

You might’ve noticed that I read .json files, those are 9 possible json inputs that I came up with. They look very similar to the json response example above, just with some missing fields.

And it’s better to store those as separate files, looks much cleaner. Here’s a FileReader util to read a json file to a string

Implementation

After several iterations similar to what we did with first example – here’s what I got for my extractLocation method


android local tests

Process

So after writing those few test here’s what I learned: yes, it is better to start with tests. First create an actual method stub, of course, and then think of all the possible inputs and the results they should give. Here comes the naming I used methodNameThatYouTest_Input_ExpectedResult()

And yes, it’s much better to write a separate method for each input. First of all to keep tests as readable as possible and second – to keep tests flat, so that there’s less room for failure. Yes, you can write wrong test as well. That’s why you start by writing tests and keep them short, this way it will be very unlikely that you write wrong tests

And only after you completed writing tests  – you start implementing code. Because you definitely don’t want to jump back and forth by adding additional tests

Why Should You Care

The first time it will be a bit of a struggle: but the result is – code that gives predictable output and you not having to actually do manual testing in your app! Which will save you time even if you’re slow in writing tests

Imagine this: you wrote a json parser method, but it was wrong. You didn’t know about it and kept working on your app, implementing UI. Now when it came to the point of running it and checking the result – your get a crash. And here the fun begins: you start debugging it. It’s good when your code base is simple, but when you have your own server and an app – now there’re two points of failure. You might waste the time just figuring out whether it’s an Android or backend error

All this could be eliminated by writing unit tests. By the way, it was pretty fun too. You can come up with numerous amount of tests. I hope you start to get the point. Because it takes mostly practice to understand it

 

You can get the source code here. In the following posts, we’ll go through writing tests with Mockito. Don’t forget to subscribe, follow me on Twitter, Facebook, G+ to get the latest updates