11

I have split a project, based on Spring Boot, into several Maven modules. Now only the war-project contains a starter class (having a main method, starting Spring), the other modules are of type jar.

How do I test the jar projects, if they don't include a starter?

Example JUnit test case header:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(StarterClassInDifferentProject.class)
...
Stefan
  • 12,108
  • 5
  • 47
  • 66

3 Answers3

14

I think context tests should be available per module so you can find issues with wire and configuration early on and not depend on your full application tests to find them.

I worked around this issue with a test application class in the same module. Make sure this main class is in your test dir.

@SpringBootApplication
public class TestApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
}

your context should work now.

@RunWith(SpringRunner.class)
@ActiveProfiles(profiles = {Profiles.WEB_REST})
@WebMvcTest(EntityController.class)
@DirtiesContext
public class ServicesControllerTest {

    @Autowired
    private MockMvc mvc;

    @MockBean
    private Controller controller;

    @Test
    public void testAll() throws Exception {
        given(controller.process(null)).willReturn(null);

        mvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk());
    }
}
Community
  • 1
  • 1
Gadi
  • 1,539
  • 22
  • 37
6

I solved a similar situation. I have a project with two modules:

  1. a "lib" project with domain and utilities classes,
  2. a "web" projects with a spring boot application, templates, controllers, etc...

and I wanted to test the "lib" project in a spring-boot-test fashion.

First, include the required dependencies with scope "test" in the pom.xml (in my case there is also the H2 database):

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <version>1.3.3.RELEASE</version>
        <scope>test</scope>
    </dependency>
    <!-- add also add this here, even if in my project it is already present as a regular dependency -->
     <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
        <version>1.3.3.RELEASE</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>1.4.191</version>
        <scope>test</scope>
    </dependency>

For testing purposes, among the test sources of the "lib" project, I have a class that acts as my test configuration

    package my.pack.utils;

    import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
    import org.springframework.boot.autoconfigure.domain.EntityScan;
    import org.springframework.boot.test.context.TestConfiguration;
    import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

    @TestConfiguration
    @EnableJpaRepositories(basePackages = {"my.pack.engine.storage", "my.pack.storage"})
    @EntityScan(basePackages = {"my.pack.storage", "my.pack.entity"})
    @EnableAutoConfiguration
    public class MyTestConfiguration
    {

    }

This sets up the H2 database in order to test the data access functionalities of the application

Finally, only in the test classes where I find it useful, I configure the execution to use the test configuration (I do not always need to do that, but sometimes it is handy):

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = MyTestConfiguration.class)
    public class TestAClassThatNeedsSpringRepositories
    {
        // tests...
    }
lrkwz
  • 6,105
  • 3
  • 36
  • 59
Evil Toad
  • 3,053
  • 2
  • 19
  • 28
0

The question is

How do I test the jar projects, if they don't include a starter?

I believe the right answer, is that your jar submodules should not be united tested with spring-boot context.

In fact, most if not all tests in your jar projects should not even use the RunWith(Spring...) They should be vanilla or using a mock library such as @RunWith(MockitoJUnitRunner.class).

If you read SpringApplicationConfiguration's javadoc:

Class-level annotation that is used to determine how to load and configure an ApplicationContext for integration tests.

It is considered integration testing.

Other than that, you can also launch your tests using spring context (not spring-boot) with a 'test spring configuration' in your jar submodule. Define your beans/resources and use it in your test.

@RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(TestConfigInJarModule.class)

For instance, I do this to test Spring data Repositories, using a test spring configuration (without dependencies on spring-boot).

alexbt
  • 16,415
  • 6
  • 78
  • 87
  • 1
    BTW, you can still choose to include spring-boot dependencies in your submodules in test scope, and unit test with it! – alexbt Jun 03 '16 at 16:41
  • I disagree, I think modular application should be tested module by module even with application context. you can find issues with configuration early on and not wait for a full application tests. – Gadi Sep 27 '16 at 09:15
  • I see what you mean, and I agree with the more tests the better! (Doesn't matter if they are unit, intg...). The thing is, we're talking about "Spring boot" and most of the configuration is in the application.properties, not visible to submodules. Using @SpringBootTest in submodules will require a specific setup for tests and then I'm not so sure you're actually testing your productions context anymore. Your 'test' context may very well work while your production one fails. Please do reply your thoughts on this. – alexbt Sep 27 '16 at 10:11
  • One thing I almost always do kick start with SpringBoot is the persistence layer (spring data repo) backed by a memory database, all setup from the application.properties. It allows me to test save/find... and mostly serves the purposes of validating my jpa model (same goes any other persistence implementation such as mongodb, SOLR...). The main reason I kick start with SpringBoot Boot is because how simple its configuration is, but it does not test the production spring conext at all. – alexbt Sep 27 '16 at 10:20
  • We divide our applications with profiles and we include configuration element per profile so core configuration goes with core and jpa config goes with jpa. Spring is very good scanning our modules for configuration classes and pick all the necessary configs. another reason to do tests in the module context without the application. – Gadi Sep 27 '16 at 18:32