Injection in tests not working?

717 views
Skip to first unread message

wtr...@gmail.com

unread,
Jun 23, 2015, 3:23:38 AM6/23/15
to dropwiz...@googlegroups.com
Hey Guys,

I've an issue on testing my resource. The issue is about injecting and mocking variable in my resource code. As examples helping most to explain issues, see consecutively.

Pretend I've (minimal) Resource like this one:
```java
@Path("/myURL")
@Produces(MediaType.APPLICATION_JSON)
public class ExportResource {

    // ----------------------------------------------
    // CONSTANTS
    // ----------------------------------------------
    /** Resource-Logger. */
    protected static final Logger LOGGER = LoggerFactory
            .getLogger(AbstractExportResource.class);

    // ----------------------------------------------
    // Class Variables
    // ----------------------------------------------
    @Inject
    protected Subject subject;

// methods not given, as they are not necessary here
}
```

Injection works fine, as I'm using this (minimal) Application code:
```java
public class ExportApplication extends
        Application<ExportConfiguration> {

    public static void main(String[] args) throws Exception {
        new ExportApplication().run(args);
    }

    @Override
    public String getName() {
        return "Export";
    }

    @Override
    public void initialize(Bootstrap<ExportServiceConfiguration> bootstrap) {
        // nothing to do yet
    }

    @Override
    public void run(ExportServiceConfiguration configuration,
            Environment environment) {

        final Client httpClient = new JerseyClientBuilder(environment).using(
                configuration.getJerseyClientConfiguration()).build(getName());
       
        // register Subject as SubjectFactory
        environment.jersey().register(new AbstractBinder() {
            @Override
            protected void configure() {
                bindFactory(SubjectFactory.class).to(Subject.class).in(RequestScoped.class).proxy(true);
            }
        });
       
        // register resource
        environment.jersey().register(
                new ExportResource(httpClient, configuration));
    }// run
}// ExportApplication
```
Just to provide full code, see (minimal) SubjectFactory:
```java
public class SubjectFactory implements Factory<Subject> {

    @Inject
    private  HttpServletRequest request;

    @Override
    public Subject provide() {
        Subject s = new Subject();
        s.setName("Paul");
        return s;
    }

    @Override
    public void dispose(Subject instance) {
    }
}
```

and (minimal) Subject:
```java
public class Subject {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
```
If I want to test the resource, I'm using ResourceTestRule:

```java
RunWith(MockitoJUnitRunner.class)
public class ExportTest {

    protected static final ExportConfiguration configuration = new ExportConfiguration();

    @Mock (name="subject")
    protected static final Subject subject = mock(Subject.class);

    // ----------------------------------------------------
    // JUNIT specific variables
    // ----------------------------------------------------
    @InjectMocks
    private static ExportResource exportResource = new ExportResource();

    @ClassRule
    public static final ResourceTestRule resources = ResourceTestRule.builder()
            .addResource(exportResource).build();

    @Before
    public void setup() throws Exception {       
        MockitoAnnotations.initMocks(this);
        reset(subject);
    }// setup
    @AfterClass
    public static void tearDownClass() {
        // nothing to do atm
    }

    @Test
    public void testSuccessTestConnection() {
        Response response = resources.client().target("/myURL/test")
                .request().get(Response.class);

        /** Check: Response.getCode = 200 */
        Assert.assertEquals("Different status code expected", 200,
                response.getStatus());
    }// testSuccessTestConnection
}
```

Doesn't work, as I get faced with this error:
```
MultiException stack 1 of 1
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=Subject,parent=AbstractExportResource,qualifiers={},position=-1,optional=false,self=false,unqualified=null,1921028872)
    at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:74)
    at org.jvnet.hk2.internal.Utilities.justInject(Utilities.java:945)
    at org.jvnet.hk2.internal.ServiceLocatorImpl.inject(ServiceLocatorImpl.java:923)
    at org.jvnet.hk2.internal.ServiceLocatorImpl.inject(ServiceLocatorImpl.java:913)
    at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:575)
    at org.glassfish.jersey.server.ApplicationHandler.access$500(ApplicationHandler.java:166)
    at org.glassfish.jersey.server.ApplicationHandler$3.run(ApplicationHandler.java:327)
    at org.glassfish.jersey.internal.Errors$2.call(Errors.java:289)
    at org.glassfish.jersey.internal.Errors$2.call(Errors.java:286)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.processWithException(Errors.java:286)
    at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:324)
    at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:277)
    at org.glassfish.jersey.test.inmemory.InMemoryTestContainerFactory$InMemoryTestContainer.<init>(InMemoryTestContainerFactory.java:77)
    at org.glassfish.jersey.test.inmemory.InMemoryTestContainerFactory$InMemoryTestContainer.<init>(InMemoryTestContainerFactory.java:63)
    at org.glassfish.jersey.test.inmemory.InMemoryTestContainerFactory.create(InMemoryTestContainerFactory.java:111)
    at org.glassfish.jersey.test.JerseyTest.createTestContainer(JerseyTest.java:277)
    at org.glassfish.jersey.test.JerseyTest.setUp(JerseyTest.java:609)
    at io.dropwizard.testing.junit.ResourceTestRule$1.evaluate(ResourceTestRule.java:198)
    at org.junit.rules.RunRules.evaluate(RunRules.java:20)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
    at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
```

Obviously, the injection is not working. After googling for a while and doing research on this topic it has turned out, injectMocks doesn't wok on static variables. And as we see above, the ResourceTestRule is static and the Rule needs to be static. Therefore, the ExportResource needs to be static as well which is causing the problem.

Do you guys know to deal with that?

Thanks in advance.

All the best!

friso.v...@gmail.com

unread,
Mar 8, 2019, 3:55:07 AM3/8/19
to dropwizard-user
Nearly four years on and I'm having the same problem. Did you find any solution for this? If so could you share it? I'm trying to do it with JUnit5, but can't really find any documentation :-(

Groeten,

Friso

friso.v...@gmail.com

unread,
Mar 21, 2019, 6:08:24 AM3/21/19
to dropwizard-user
I did manage to get mine working. For future users searching this (and in case somebody spots some way of doing it better):

@ExtendWith(DropwizardExtensionsSupport.class)
class ExportResourceTest {
   
// @formatter:off
   
public static final ResourceExtension resource = ResourceExtension.builder()
           
.addResource(new ExportResource())
           
.addResource(new AbstractBinder() {
               
@Override
               
protected void configure() {
                    bind
(mock(Subject.class)).to(Subject.class);
               
}
           
}).build(); // @formatter:on

    @Test
    void test() {
        Response response = resource.target("/some/path").request().get();
        assertThat(response.getStatusInfo().getFamily()).isEqualTo(Family.SUCCESSFUL);

}


did the trick for me

Reply all
Reply to author
Forward
0 new messages