Consider the following (totally contrived) example:
public class Length {
private static final int MAX_LENGTH = 10;
private final int length;
public Length(int length) {
if (length > MAX_LENGTH)
throw new IllegalArgumentException("Length too long");
this.length = length;
}
}
I would like to test that this throws an exception when called with a length greater than MAX_LENGTH. There are a number of ways this can be tested, all with disadvantages:
@Test(expected = IllegalArgumentException.class)
public void testMaxLength() {
new Length(11);
}
This replicates the constant in the testing case. If MAX_LENGTH becomes smaller this will silently no longer be an edge case. If it becomes larger this will fail and need to be changed manually (which might not be a bad thing).
These disadvantages can be avoided by adding a getter for MAX_LENGTH and then changing the test to:
new Length(Length.getMaxLength());
This seems much better as the test does not need to be changed if the constant changes. On the other hand it is exposing a constant that would otherwise be private and it has the significant flaw of testing two methods at once - the test might give a false positive if both methods are broken.
An alternative approach is to not use a constant at all but, rather, inject the dependency:
interface MaxLength {
int getMaxLength();
}
public class Length {
public static void setMaxLength(MaxLength maxLength);
}
Then the 'constant' can be mocked as part of the test (example here using Mockito):
MaxLength mockedLength = mock(MaxLength.class);
when(mokedLength.getMaxLength()).thenReturn(17);
Length.setMaxLength(mockedLength);
new Length(18);
This seems to be adding a lot of complexity for not a lot of value (assuming there's no other reason to inject the dependency).
At this stage my preference is to use the second approach of exposing the constants rather than hardcoding the values in the test. But this does not seem ideal to me. Is there a better alternative? Or is the lack of testability of these cases demonstrating a design flaw?
Aucun commentaire:
Enregistrer un commentaire