victorio
victorio

Reputation: 6646

How to use the SpringBoot's context for testing by JerseyTest

I have some @Component and @Resource in my SpringBoot application. I have the right JDBC datasource, and also I have some REST services, by Jersey. I want to test one of the services, but it will fail, it says:

Injection of autowired dependencies failed

But it does not use any component.

This is a simple test for testing db, and it is working:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApplication.class)
public class CommonRepositoryTest {

    @Autowired
    private MyRepository myRepository;

    @Test
    public void testDatabaseChangeLogsSize() {
        int resultSize = myRepository.getTableRowSize(MyTable.TABLE_NAME);
        System.out.println("MyTable result list size: "+resultSize);
        assertTrue("MyTable table should has at least one row!", resultSize>0);
    }

}

But this REST tester is not working:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApplication.class)
public class SampleResourceTest extends JerseyTest {

    @Override
    protected Application configure() {
        ApplicationContext context = new AnnotationConfigApplicationContext(MyApplication.class);
        return new ResourceConfig(SampleResource.class).property("contextConfig", context);
    }

    @Test
    public void testSampleGet() throws Exception {
        long id = 1;
        String name = "name";
        SampleDomainModel sampleDomainModel = new SampleDomainModel();
        sampleDomainModel.setId(id);
        sampleDomainModel.setName(name);
        Response response = target("/sampleresource/samplepath/" + id).queryParam(name).request().get(Response.class);
        SampleDomainModel responseSampleDomainModel = response.readEntity(SampleDomainModel.class);
        assertEquals(sampleDomainModel.getId(), responseSampleDomainModel.getId());
    }

}

As you see, it must override the configure() method from JerseyTest. I think the problam is, that the AnnotationConfigApplicationContext cannot load anything maybe (?). The @SpringApplicationConfiguration(classes = MyApplication.class) annotation loads the context, but the new AnnotationConfigApplicationContext(MyApplication.class) code maybe do the failure, it does not have the full context.

If I replace the code with mocking, it works (but it is not a nice way):

@Override
protected Application configure() {
    ApplicationContext mockContext = Mockito.mock(ApplicationContext.class);
    return new ResourceConfig(SampleResource.class).property("contextConfig", mockContext);
}

The fail message is:

2016-05-13 13:25:39.617  WARN 9832 --- [           main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myRepositoryImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.jdbc.core.JdbcTemplate com.repository.impl.myRepositoryImpl.jdbcTemplate; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$JdbcTemplateConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$JdbcTemplateConfiguration.dataSource; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration$NonEmbeddedConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.422 sec <<< FAILURE! - in com.ws.server.SampleResourceTest
testSampleGetWithCorrectParameters(com.ws.server.SampleResourceTest)  Time elapsed: 0.015 sec  <<< ERROR!
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myRepositoryImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.jdbc.core.JdbcTemplate com.repository.impl.MyRepositoryImpl.jdbcTemplate; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$JdbcTemplateConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$JdbcTemplateConfiguration.dataSource; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration$NonEmbeddedConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).
    at org.springframework.boot.autoconfigure.jdbc.DataSourceProperties.getDriverClassName(DataSourceProperties.java:180)
    at org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$NonEmbeddedConfiguration.dataSource(DataSourceAutoConfiguration.java:121)

How to use the SpringBoot context for this jersey test?

Upvotes: 3

Views: 3748

Answers (1)

Paul Samsotha
Paul Samsotha

Reputation: 209012

SImply put, you can't use both Spring's TestContext and Jersey Test Framework together. They will operate on two different ApplicationContexts. Even if you try to inject the ApplicationContext (created be the TestContext) into the test class and pass it to the ResourceConfig in the configure method, it's too late, as the injection doesn't occur until after construction, but the `configure method is called during contruction.

Forget JerseyTest and just use @WebIntegrationTest. See the sample from the spring boot project.

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(SampleJerseyApplication.class)
@WebIntegrationTest(randomPort = true)
public class SampleJerseyApplicationTests {

    @Value("${local.server.port}")
    private int port;

In a Jersey/Boot environment, Jersey needs to run in a web app environment, and that's what the @WebIntegrationTest does.

For the client, instead of just calling target on the JerseyTest, you will just need to create the client

Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:" + this.port);

Response response = target.path("/sampleresource/samplepath/" + id).request().get(); 

Upvotes: 4

Related Questions