Test-Driven Android Development, Part 3

Hossein Abbasi
AndroidPub
Published in
5 min readMar 7, 2019
Image by dailybackgrounds.com

In this article series, we’re going to follow this road-map:

  1. Fundamentals of Test Driven Development(TDD)
  2. Designing for Test
  3. Introduction to Unit Testing
  4. Behavior-Driven Development(BDD)
  5. Add-ins & Plug-ins
  6. Testing Beyond the Unit Test

If you haven’t read the previous series, it would be nice to take a look.

Introduction to Unit Testing

Fundamentals of Unit Testing? Some syntaxes? What is Assert? JUnit Syntax, Annotations, and Setup.

JUnit Features:

  • Fixtures: Prerequisite setup for running tests. Like, create a connection to the JSON feed.
  • Test Suites: Aggregate tests together. So, we can run all of the tests at once.
  • Test Runners: Run our JUnit tests. But it’s not always necessary in Android Studio cause lots of running tests is built-in into AS automatically; All we need is right click on the test and click Run.
  • Test Classes: The classes we’re writing our tests, Assert methods(is expected value equals to actual value?), TestCases(fixtures-which in JUnit3 we had to extend TestCase class but in JUnit4 just annotations), TestResults(Aggregates the result of running tests)
Image by rpktech.com

Now we’re going to test our AlbumDao.

Notes:

  • The TestAlbumDao is created under test folder.
  • We used the Stub class to prevent sending the request to the actual server.
  • The method name should describe what it’s doing.
  • The setup method will run before each test.
  • assertValueCount assert that this TestObserver/TestSubscriber received the specified number onNext events or not.
  • With the help of backtick (`), we can write the name of methods as a regular sentence with space.

Another one to check is the first album of the user with user id 1 equals to what we expected or not:

Notes:

  • The albumMocked content is the one which we set in AlbumDaoStubImplclass.
  • The assertResult assert that the Single is being subscribed to, emits the specified value, completes and has no errors. I mean this: .assertSubscribed()
    .assertValues(something)
    .assertComplete()
    .assertNoErrors()
  • test() creates a TestObserver and subscribes it to the Single. Remember that it does not operate by default on a particular Scheduler.
  • If you don’t want to the Single to be completed, you can use assertValuesOnly(something).
  • remember to initial the albumDao with the real AlbumDaoImpl, not the AlbumDaoStubImpl. We’re going to do TDD, so it must stop us and force us to implement the necessary classes and methods. On the other hand, cause we have implemented AlbumDaoImpl in the previous article, we allow to use it.

For last note(↑):

If you want to test your API calls deeply, instead of the previous approach, you can use MockWebServer. Let’s do it one more time in this way:

Note:

  • Don’t forget to pass testObserver into albumDao.getAlbums("").subscribe(HERE)

Remember that when you’re using Rx library, there are various solutions to testing your code, such as using RxAndroidPlugins or using Transformers as we have already done in one of the other articles of mine.

About Transformers, I mean explicitly pass schedulers(which wrap real schedulers) to presenters or wherever you want using Dependency Injection. Another point is using io or computation schedulers will call the method on the different thread what may cause the test to fail unexpectedly. Why? This happens because in that case, the defined method may (not always!) run after assertions in the test. So, what can we do is using trampoline(by calling Schedulers.trampoline()) which executes all tasks in a FIFO way on the same thread that you called your method one after another.

trampoline(): Returns a default, shared Scheduler instance whose Scheduler.Worker instances queue work and execute them in a FIFO manner on one of the participating threads.

Note: If you’re using such these methods: delay, throttle, timeout or debounce (which uses Schedulers.computation() or Schedulers.io() internally), you have to explicitly pass scheduler to such methods(as a third parameter).

The way when we’re using Mockito2 and RxAndroidPlugins and want to test our AlbumService:

And if you want to test in the case of a Network Error:

Note:

  • Remember to enable MockMaker plugin from Mockito2 extensions. Of course, you can try PowerMock library without creating that extra resource file.
  • If you’re following that approach that I’ve commented in the above snippet code, you have to pass an exception which is extended from Exception, cause MockitoException is extended from that.
  • Remember to mock your API Service, otherwise, you’ll get MissingMethodInvocationException: when() requires an argument which has to be ‘a method call on a mock’.

What’s Next?

On the next article, we’ll go through “Behavior-Driven Development(BDD)”.

Thank you for taking your precious time to read this article. Please clap your 👏 and help others find this article too.

References:

  • Unit Testing asynchronous RxJava code by Paulina Sadowska
  • TDD by Brandan Jones

--

--