Reputation: 48428
I'm just getting started with Java, and I'm confused about how to unit test Java classes while still keeping everything isolated. Specifically, I'm wondering how I might test a method like createProgram
in this example:
package com.example.app;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import com.example.data_models.Program;
public class ProgramCreator {
private PersistenceManagerFactory pm_factory;
public ProgramCreator(PersistenceManagerFactory pm_factory) {
this.pm_factory = pm_factory;
}
public void createProgram(String name, String instructor, double price) {
PersistenceManager pm = getPersistenceManager();
try {
pm.makePersistent(new Program(name, instructor, price));
} finally {
pm.close();
}
}
private PersistenceManager getPersistenceManager()
{
return this.pm_factory.getPersistenceManager();
}
}
I'm pretty sure I can mock out the persistence manager factory using a library like mockito
and use that to test that the makePersistent
method is getting called with the right arguments, but how do I check that the fields of the program data model are correct while still keeping everything isolated? I don't want to rely on the program object's getter methods, as that would result in my unit tests for ProgramCreator
being reliant on the Program
class being correct. What do I do in this situation? (With Ruby, I'd probably just stub out the new
method of the Program
class. Is something like that possible in Java?)
Upvotes: 0
Views: 193
Reputation: 570
By creating an object (Program) in createProgram method you are creating tight coupling between the objects. Instead delegate the work of creation to a factory and you can mock the factory in your unit test. This would mean we would be testing only what createProgram method is doing and nothing else. Trying to unit test code could give us indications to re-design/re-factor the code.
public class ProgramCreator {
private PersistenceManagerFactory pm_factory;
private ProgramFactory p_factory;
public ProgramCreator(PersistenceManagerFactory pm_factory, ProgramFactory pFactory) {
this.pm_factory = pm_factory;
this.p_factory = pFactory;
}
public void createProgram(String name, String instructor, double price) {
PersistenceManager pm = getPersistenceManager();
try {
pm.makePersistent(p_Factory.createProgram(name, instructor, price));
} finally {
pm.close();
}
}
}
Upvotes: 1
Reputation: 44448
You don't have to test everything, everywhere.
Do as you say: mock the appropriate code to test createProgram
and see if the results of that are as you expect them to be (aka: there has been a program persisted with the given fields).
You don't have to necessarily test that you actually create a new Program
that has those fields. You could just as well test in a different method whether or not new Program(name, instructor, price)
creates a new object with the right values.
The most important part about unit tests is this flow:
-> General idea
-> Logic performed
-> End situation reached
Your situation fills this in as
-> I want to test createProgram
with variables X, Y and Z
-> ??
-> The database should return a program that has values X, Y and Z
All together you don't really care what happens in the second step, as long as the end result works. For this reason you can allow more general tests in your code that basically perform logic and check if the result of all that equals your desired output.
The obvious issue with this is ofcourse: in the case of an error, won't this mean I have to manually debug to find the issue? Yes, it does. That's why you should add many smaller tests (like testing the constructor) to help pinpoint the exact issue.
There certainly is nothing wrong with using getters and setters. In fact, you will most certainly need them. It's about testing workflow, not necessarily testing isolated methods.
Upvotes: 0
Reputation: 13272
A unit in is not necessarily limited to a single class, it is the smallest set of classes that work together. So there is nothing wrong with using the getters from Program
while testing ProgramCreator
.
Upvotes: 1