Test-Driven Android Development, Part 3
In this article series, we’re going to follow this road-map:
- Fundamentals of Test Driven Development(TDD)
- Designing for Test
- Introduction to Unit Testing
- Behavior-Driven Development(BDD)
- Add-ins & Plug-ins
- 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)
Now we’re going to test our AlbumDao
.
Notes:
- The
TestAlbumDao
is created undertest
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 numberonNext
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 inAlbumDaoStubImpl
class. - 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 realAlbumDaoImpl
, not theAlbumDaoStubImpl
. 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 implementedAlbumDaoImpl
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
intoalbumDao.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 whoseScheduler.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
, causeMockitoException
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