I have this class:
public class A {
private int x;
public A(int x) {
this.x = x;
}
}
And a method in a different class I want to test:
public class B {
public List underTest() {
int x = doStuff();
return Collections.singletonList(new A(x));
}
private int doStuff() { /* ... */ }
}
I want to test that, at the end of underTest()
, the item in the returned list contains an x
field equal to a certain value. I've written this:
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.is;
@Test
public void Test1() {
List result = bInstance.underTest();
assertThat(result, contains(hasProperty("x", is(1))));
}
But junit complains that item 0: No Property "x"
for my test case.
How can I test this? The only thing I can think of is to add a public getter for getX()
, then iterate through the returned List
and check every element. Remember that, while the method returns a singletonList
, the return type is just List
, so it could be changed in the future to have multiple values in it.
I think it's first worth saying that testing class internals like this is not a good idea, except maybe in very special cases. Your tests will be brittle and changes that would normally be totally safe - i.e. renaming a field - may now cause your automated build to fail. You should test external behaviour, not implementation details.
It seems like you'd be better off implementing equals
and hashCode
in your class A
, so then you can simply do:
contains(new A(1))
With that said, if you do have a genuinely good reason to do this (and such cases will be rare) then you cannot use hasProperty
for this.
From the JavaDoc:
Creates a matcher that matches when the examined object has a JavaBean property with the specified name whose value satisfies the specified matcher.
I believe this implies that you would need a method named getX
.
You shouldn't add such a method just for the purpose of a test, but you can write your own general-purpose Matcher
implementation that will use reflection to examine the fields of the class.
Here is a sample implementation:
class ReflectiveFieldMatcher<T> extends BaseMatcher<Object>
{
private final String fieldName;
private final T expectedValue;
ReflectiveFieldMatcher(final String fieldName, final T expectedValue)
{
this.fieldName = fieldName;
this.expectedValue = expectedValue;
}
@Override
public boolean matches(final Object obj)
{
for (final Field field : obj.getClass().getFields())
{
if (field.getName().equals(fieldName))
{
field.setAccessible(true);
try
{
Object value = field.get(obj);
return expectedValue.equals(value);
}
catch (final IllegalAccessException e)
{
throw new RuntimeException(e);
}
}
}
return false;
}
@Override
public void describeTo(final Description description)
{
description.appendText("Object with field '" + fieldName + "' with value: " + expectedValue);
}
}
Your example would now look like this:
assertThat(result, contains(new ReflectiveFieldMatcher<>("x", 1)));