How to unit test JSON parsing

All you need to do is add the following line to the dependency section in your build.gradle:

testImplementation 'org.json:json:20180813'

Note that you also need to use Android Studio 1.1 or higher and at least build tools version 22.0.0 or above for this to work!

testImplementation means that the dependency is included as a test dependency will only be used when your project is being compiled for executing unit tests. The supplied jar will not be included in your APK and will only be used to replace the missing classes in the org.json package.


Edit: see updated answer at the end

I've found the answer to this one. It doesn't solve my problem, but at least it explains why there is a problem.

First, I made the faulty assumption that the JSONObject (imported from the org.json package) was included as a part of the JRE. It isn't - in an Android project, this resides in android.jar (classic "duh" moment).

This discovery boosted my self confidence a bit. This could easily be solved by adding a reference to the android.jar in my unit test project - or at least so I thought for a brief moment. Doing so only gave me another error when running my test:

java.lang.RuntimeException: Stub!
    at org.json.JSONObject.<init>(JSONObject.java:8)
    ...

At least this gave me something more to google for. What I found however, wasn't really encouraging (yet another classic "duh" moment)...

This blog describes the problem pretty well: Why Android isn’t ready for TDD, and how I tried anyway. If you don't bother to read the whole thing, the brief explanation is as follows:

The problem here is that the android.jar supplied with the SDK is stubbed out with no implementation code. The solution that seems to be expected is that you should run your unit tests on the emulator or a real phone.

When further doing some googling with this in mind, I found several articles, blogs and also questions here on SO regarding the issue. I'll add a few links here at the end, for those that might be looking:

  • android.jar In The SDK Only Has The API And Not The Implementation?
  • Can I use android.os.* libraries in a standalone project?
  • AndroidTesting
  • Eclipse + Android + JUnit test references android.os class = NoClassDefFoundError (not sure why on earth I didn't find this one when I initially wrote my question, I must have been completely lost...)

And there are plenty more if you look around.

There are several suggestions/solution/alternative approaches to unit testing in Android in many of those links, but I won't bother to try to make a good answer based on that (as there is obviously way too much I still don't know about Android development). If anybody has any nice tips though, I'll be glad to hear about them :)

UPDATE:
After experimenting a bit more, I actually managed to find a working solution to this specific problem. The reason why I didn't try this in the first place, was that I thought I had read somewhere that it would be problematic to include "normal" java libraries in my Android app. I was trying so many different things to get around my problem, so I thought I'd just give this a try as well - and it actually worked! Here is how:

  • I downloaded the source for the "real" org.json package from here: http://www.json.org/java/index.html
  • Next I compiled the source code and packed it together in my own json.jar
  • I added the newly created json.jar to the build path of my project (the main project of my Android application, not the test project)

No changes to my code, no changes to my test, only adding this library. And everything works, both my Android app and my unit tests.

I also tested stepping through the code in debug mode, and when debugging the Android app the JSONObject in my JsonCourseParser is fetched from the Android SDK (android.jar), but when debugging my unit test it is fetched from my own json.jar. Not sure if this means that the json.jar isn't included when my app is built, or if the runtime intelligently selects the correct library to use. Also not sure if this extra library might have any other effects on my final app. I guess only time will tell...