javaguicejsr330hk2

Unit testing JSR-330 injected objects


I have previously used Spring DI, and one of the benefits I perceive is that I can test my Spring bean classes without involving Spring (imports omitted for brevity):

public class Foo {
    private String field;

    public void setField(String field) { this.field = field; }
    public String getField() { return field; }
} 

public class TestFoo {
    @Test
    public void test_field_is_set() {
       Foo foo = new Foo();
       foo.setField("Bar");
       assertEquals("Bar", foo.getField());
    }
}

Now I am experimenting with JSR-330, which means not explicitly writing setters.

I'm using Hk2 so far, purely because of some anecdotal stuff about Jersey being tied to Hk2, and making it difficult to co-habit with other JSR-330 implementations.

public class Foo {
   @Inject 
   private String field;
}

I half expected some magic to happen, whereby the @Inject annotation caused a setter to become available, but this is not the case:

Foo foo = new Foo();
foo.setField("Bar"); // method setField(String) is undefined for the type Foo

Solution

  • It turns out that frameworks relying on private/protected field access are not so uncommon. Hibernate, JPA, several JSR-330 implementations, including Spring itself, all do it.

    Spring's spring-test package provides a ReflectionTestUtils class containing static methods for accessing these fields.

    Using this one can test the class in the question thus:

    import static org.springframework.test.util.ReflectionTestUtils.*;
    
    ...
    
    @Test
    public void testUsingSpringReflectionTestUtils() {
        Foo foo = new Foo();
        setField(foo, "field", "Bar");
        assertEquals("Bar", foo.getField());
    }
    

    You need spring-test and spring-core in your test classpath for this to work, but it doesn't add a dependency on Spring for your production code.

    (Comments welcome about alternative implementations of the same principle welcome. I don't think it's worth rolling one's own, however simple it would be, given that Spring has a good implementation.)