I want to write a test for the following method:
public void addItem(Item item) {
items.add(0, item);
DatabaseHelper.getInstance().writeOneItem(item);
}
The class is called ItemManager and it's responsibility is to manage Items that the user can save to or remove from a list. It should be kept in sync with an Sqlite database that persists the items on the list.
When the DatabaseHelper
(ormlite) is not inited with init(Context context)
(which is usually sone when my Andoid app starts, but is not done in my test), it's getInstance()
method will return null
and the method execution from above will crash.
What should I do here? I could just call init(Context context)
from my test or check if DatabaseManager.getInstance()
is null before calling anything on it. But that seems more like a workaround. It seems to me like I shouldn't do any Database stuff in this method and try to seperate the ItemManager from the Database as much as possible.
Any ideas on how the ideal solution would look, not in form of a concrete implementation but from a gerneral design standpoint?
I'm new to unit testing and having a hard time decoupling stuff from each other.
In my opinion, your class ItemManager
has to call the DatabaseHelper
to write the item but your unit test just want to make sure that it does. You don't want to test that the DatabaseHelper
actually writes the item in the database, that would be another test.
I would modify the design of your class: the DatabaseHelper.getInstance()
should not be done directly in the method. Your ItemManager
should have a private field with the instance of the DatabaseHelper
. That way you can mock it and verify that it is called.
Using Mockito for example:
public void addItem(Item item) {
items.add(0, item);
this.databaseHelper.writeOneItem(item);
}
@Test
public void my_test() {
// GIVEN
DatabaseHelper databaseHelper = mock(DatbaseHelper.class);
ItemManager manager = new ItemManager(databaseHelper);
Item item = new Item()
// WHEN
manager.addItem(item);
// THEN
verify(databaseHelper).writeOneItem(item); // This verifies that the method writeOneItem of the "mock" is called with the "item" parameter
}
// Another test would check that the item is added to the "items" collection
Your unit test should be focused on testing ONE method and not the behaviour of the classes it uses.
In my example, I inject the DatabaseHelper
in the ItemManager
via constructor but you could use any method: constructor, setter, dependency injection framework, etc.
Break the static dependance and use a mock framework (like mockito)
class ItemManager {
...
// decoupling
private DatabaseHelper instance = DatabaseHelper.getInstance();
public void addItem(Item item) {
items.add(0, item);
instance.writeOneItem(item);
}
}
With mockito :
class ItemManagerTest{
// declare mock service
@Mock
DatabaseHelper instance;
// inject mock service into your about to be tested class
@InjectMocks
ItemManager manager;
@Test
public void test() {
// Given
Item item = new Item();
...
// When
manager.addItem(item);
// Then
// assert that the service has been called with the right parameters
verify(instance).writeOneItem(item);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With