Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use SpringApplicationConfiguration or ContextConfiguration to load smaller app portions

I am working on a spring-boot based project, which is fairly new to me. At present, I am using the @WebApplicationContext annotation to get any of my Junit test to run, as I cannot seem to get the application to boot any other way. My goal in asking this question is to either get a distinct answer to how to avoid it's use, or links to projects use an applicable concept.

My exact goal is: I would like to have a testing configuration which will not load up the entire web application in order to test smaller services and sub sets of classes.

Example: I currently have a series of 3 assemblers. One is for a parent object, and the other two for child related objects

@Component
public class ReportResponseAssembler {

    @Autowired
    private ParameterResponseAssembler parameterResponseAssembler;

    @Autowired
    private TimeRangeResponseAssembler timeRangeResponseAssembler;

    public ReportResponseAssembler makeResponse() {
        return new ReportResponseAssembler();
    }
}

For testing purposes, I would like to load up just these 3 classes and have them appropriately inject the dependencies into the parent. Something like:

public class ReportResponseAssemblerTest {

    @Autowired
    ReportInstanceResponseAssembler reportResponseAssembler;

    @Test
    public void testPlaceHolder() {
        Assert.assertNotNull(reportResponseAssembler);
    }
}

I have attempted something along the lines of:

@EnableAutoConfiguration
@ComponentScan(basePackages = { "com.blahpackage.service.assembler" })
@Configuration
public class TestContextConfiguration {}

Then feeding this to SpringApplicationConfiguration, but even with the scan it does not detect the applicable beans for auto injection. Perhaps I need to denote them as @Beans directly in the configuration and return new instances? Are there other good ways? Any links to example projects or explanations you have would be excellent.

Thank you, any who respond, so much for your time.

like image 564
kung_fu_mike Avatar asked Oct 14 '14 21:10

kung_fu_mike


People also ask

Why do we use @ContextConfiguration?

@ContextConfiguration defines class-level metadata that is used to determine how to load and configure an ApplicationContext for integration tests.

What is the use of @configuration in spring boot?

@SpringBootApplication is a convenience annotation that adds all of the following: @Configuration : Tags the class as a source of bean definitions for the application context. @EnableAutoConfiguration : Tells Spring Boot to start adding beans based on classpath settings, other beans, and various property settings.

How do I apply application properties in spring boot?

Step 1 − After creating an executable JAR file, run it by using the command java –jar <JARFILE>. Step 2 − Use the command given in the screenshot given below to change the port number for Spring Boot application by using command line properties.

What is relaxed binding in spring boot?

Relaxed binding maps the Environment property to the bean property name even it is not an exact match. For example, dash-separated environment properties (app-name bound to appName) or capitalized properties as in PORT (bound to port). Spring boot supports relaxed binding.


2 Answers

What you are trying to do can easily be done with the following code:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestContextConfiguration.class)
public class ReportResponseAssemblerTest {

    @Autowired
    ReportInstanceResponseAssembler reportResponseAssembler;

    @Test
    public void testPlaceHolder() {
        Assert.assertNotNull(reportResponseAssembler);
    }
}

@EnableAutoConfiguration
@ComponentScan(basePackages = { "com.blahpackage.service.assembler" })
@Configuration
public class TestContextConfiguration {

}

The three classes you mention need to be under com.blahpackage.service.assembler and also have to be annotated with some Spring stereotype annotation, like @Component or @Service. For example you would have:

@Component
public class ReportResponseAssembler {

    @Autowired
    private ParameterResponseAssembler parameterResponseAssembler;

    @Autowired
    private TimeRangeResponseAssembler timeRangeResponseAssembler;

    public ReportResponseAssembler makeResponse() {
        return new ReportResponseAssembler();
    }
}

@Component
public class ParameterResponseAssembler {
   //whatever
}

I would however advise that you use such a test rarely because of the performance implications. What I mean is that if you have a lot of these types of tests, Spring needs to create and destroy a different application context for each one, whereas if you use the same context and tests, Spring can (usually) cache the context. Check out this blog post for more details

like image 55
geoand Avatar answered Oct 02 '22 09:10

geoand


I would suggest not to create testing configuration at all. Your integration tests (hopefully you know that unit test shouldn't create Spring context at all) would be testing configuration that isn't used in production.

I would suggest to create Spring configuration per package/module/integration testing unit. Than you can import these configurations into other contexts via @Import annotation.

Per package approach have huge advantage, that you can specify package private (with default access modifier) beans

@Component
class SomeBeanClass{
}

These can be autowired only by beans from same package. This is handy way how to encapsulate Spring beans.

Such granulated Spring configurations can be easily tested by your integration test in isolation.

like image 21
luboskrnac Avatar answered Oct 02 '22 11:10

luboskrnac