When creating test cases for setters and getters of instance variables within the object. What is the best approach? Here I use the get and set methods within my tests. Would this be poor testing strategy?
/**
* Test of setFlightNumber method, of class Flight.
*/
@Test
public void testSetFlightNumber() {
System.out.println("setFlightNumber");
int flightNumber = 1000;
Flight instance = new Flight();
instance.setFlightNumber(flightNumber);
// TODO review the generated test code and remove the default call to fail.
assertEquals(instance.getFlightNumber(), flightNumber);
}
/**
* Test of getFlightNumber method, of class Flight.
*/
@Test
public void testGetFlightNumber() {
System.out.println("getFlightNumber");
Flight instance = new Flight();
int expResult = 1000;
instance.setFlightNumber(1000);
int result = instance.getFlightNumber();
assertEquals(expResult, result);
}
The main principle of unit testing is that you test a simple unit of code; that is, each method should be tested on its own merits.
This means we can't use the get
method in our set
test, and vice versa - you're not testing the individual unit of code that is the single method.
Given that...
Let's say we have a PlainOldJavaObject
with a field value
that we want (for some reason) to test the validity of setters and getters for. The only appropriate way to do this is through the use of reflection.
Here's my class declaration, which is pretty skinny:
public class PlainOldJavaObject {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
I now set up my test class to make use of reflection; specifically using the Field
class:
public class PlainOldJavaObjectTest {
@Test
public void testSetter_setsProperly() throws NoSuchFieldException, IllegalAccessException {
//given
final PlainOldJavaObject pojo = new PlainOldJavaObject();
//when
pojo.setValue("foo");
//then
final Field field = pojo.getClass().getDeclaredField("value");
field.setAccessible(true);
assertEquals("Fields didn't match", field.get(pojo), "foo");
}
@Test
public void testGetter_getsValue() throws NoSuchFieldException, IllegalAccessException {
//given
final PlainOldJavaObject pojo = new PlainOldJavaObject();
final Field field = pojo.getClass().getDeclaredField("value");
field.setAccessible(true);
field.set(pojo, "magic_values");
//when
final String result = pojo.getValue();
//then
assertEquals("field wasn't retrieved properly", result, "magic_values");
}
}
In the first test, I am making certain that the field is read by reflectively accessing the value contained in the field for the instance of PlainOldJavaObject
. Without violating the integrity of the declared class*, I am confident that the field is being set appropriately.
In the second test, I assume that the value has already been set to something prior, so the set-up involves populating the field with a known default value. When I read the value back, I am asserting that the value read back is the value that we know it was originally set to.
Ultimately, if you have a lot of setters and getters, you'll have to do code like this (since, if you rely on the assumption that your setters and getters "just work", like you are in your tests above, your test cases may be invalid).
*: Mind you, reflection is a quick and fast way to get into extreme trouble with undefined behavior, and you have few guarantees of object immutability. You're taking the shrink wrap off of the language and are doing strange and unusual things. Proceed at your own peril.
Use Bean Runner API
This will automatically test all the getters and setters making sure that the values are properly set.
testBean
public void testBean(java.lang.Object bean)
throws java.lang.Exception
Test the properties that have both getters and setters. Exclude those who have been excluded by excludeProperty(String). If the object implements Serializable, do a check to ensure it really is.
Parameters:
bean - the object to test
Throws:
java.lang.Exception - on failure
I believe that getter / setter testing does have value in that it could catch typo errors. However very little time should be spent on them since these errors are not frequent due to code generation tools. Hence using a tool to execute these test rather than writing them yourself is good practice.
This is why I created a ReflectiveGetterSetterTester
which has a method testAllGetterSetters
ReflectiveGetterSetterTester
Couple other notes...
- There is no need to use two test methods. Use one since it will exersize both the getter and setter.
- Consider using a
Theory
to test a range of valid values (0, 1, Integer.MAX_VALUE
). You might also use TestedOn to pass those int in-line example here
- Test error conditions like passing
-1
the problem is that you have no way of knowing in either test whether the issue is in your getter or is in your setter, since you have to use one to test the other. you can either
use reflection
mark your private field as protected and have your test inherit from the target,
or don't test getters and setters
I'm still not experienced enough to tell what the best one is,
but I know they all have drawbacks.