Sometimes, there are classes that can’t be tested normally. Maybe it’s because there’s not many public methods, there’s an instance that can only run in the production code, or some other reasons. In this short article I want to share with you my experience writing tests with a powerful testing tool called Mockito.
Currently I’m working on a flutter project, and I have this
ActivityItemHelper class that I want to test.
DatabaseProvider is a service to create, configure, and get the database. If the code is like that, I have no way to test
The only public methods in ActivityItemHelper are
queryAll() . I can check the return output of
queryAll(), but it also doesn’t work because getting the database from DatabaseProvider only works in emulator.
Then, I remember something about testing in Advanced Programming class, which is about Mockito. With Mockito, you can create an object that acts like the real service. A mock object returns a dummy data corresponding to some dummy input passed to it. But, before I can test
ActivityItemHelper with Mockito, I need to change the implementation so that when I call insert(), it calls the Mock object, not the actual service. The service I’m talking about is
To install mockito in my Flutter project, I added this to my
pubspec.yaml file in
To insert a mocked object of
DatabaseProvider, we can use a technique called dependency injection.
In software engineering, dependency injection is a technique in which an object receives other objects that it depends on. These other objects are called dependencies. In the typical “using” relationship the receiving object is called a client and the passed (that is, “injected”) object is called a service.
To implement dependency injection in
ActivityItemHelper class, we just need to change its constructor.
As you can see at line number 2 and 4, we insert dbProvider our self. So in the implementation, we use
ActivityItemHelper(dbProvider: DatabaseProvider())but inside tests, we use
Now to we can create the test. Inside the test, I want to check if the object inserted is actually correct. For that, I use sqflite_common_ffi. It’s an sqlite3 implementation that can be used for mocking tests. This is the test for
insert() that I created:
This is the insert test that I created. Here are some explanation:
- Line 3: Initialize sqflite_common_ffi.
- Line 6: Create a test database for testing purpose.
- Line 7: Create the table that I can test.
- Line 18: Create mock of
- Line 19: Returns future test database when
DatabaseProvider.databaseis called . See Line 7 of
- Line 20: Create the class to test.
- Line 28: Insert data.
- Line 30–41: Expect inserted data.
- Line 42: Close and delete database so we can run other tests.
After knowing how to write a test for
insert() , writing another test for
queryAll() is way easier.
Writing UI tests in flutter seems simple to me, but when I had to test
ActivityItemHelper, I got stuck for days. The eureka moment for me was when I realized I should inject the mock object to the class I want to test. I didn’t do it sooner because I didn’t want to change the implementation of
Thank you for reading. I hope you find this article helpful :)