Hot questions for Spring Boot Test

Top 10 Java Open Source / Spring / Spring Boot Test

Question:

Getting a compilation error in Maven:

[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR : 
[INFO] -------------------------------------------------------------
[ERROR] /C:/prototypes/demo-sse-spring-boot-master/src/test/java/com/cedric/demo/sse/SseDemoApplicationTests.java:[6,37] package org.springframework.boot.test does not exist
[ERROR] /C:/TITAN/demo-sse-spring-boot-master/src/test/java/com/cedric/demo/sse/SseDemoApplicationTests.java:[10,2] cannot find symbol
  symbol: class SpringApplicationConfiguration
[INFO] 2 errors 
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------

Maven repo seems to have the jar present:

howerever that jar doesn't have any compiled classes inside it. only META-INF dir:

Is that by design? Where do I get the jar containing SpringApplicationConfiguration class to make Maven happy?

Here's the relevant parts of my pom.xml:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.1.RELEASE</version>
        <relativePath/>
        <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>

        <dependency>
            <groupId>org.webjars.bower</groupId>
            <artifactId>jquery</artifactId>
            <version>2.1.3</version>
        </dependency>

        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>3.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.4</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

Answer:

In your release the @SpringApplicationConfiguration annotation no longer exists. The new annotations are :

@RunWith(SpringRunner.class)

@SpringBootTest(classes = YourApplicationMainClass.class)

@WebAppConfiguration

Question:

I have a spring-boot application which uses spring-boot version 1.5.9.RELEASE. To test this application I want to use junit-jupiter version 5.0.2.

For simple service tests it works without any problems. But when it comes to testing rest endpoints, I am failing. The reason is the @RunWith(SpringRunner.class) annotation, which I used with junit4 to wire the everything together.

Is there a SpringRunner for junit5 before spring-boot 2?


Update

I just stumbled over an article on how to run JUnit5 tests. Point 4 looks like a promising start.


Answer:

To migrate from JUnit 4 to JUnit 5 you can replace @RunWith(SpringRunner.class) with @ExtendWith(SpringExtension.class).

Unfortunately, spring-boot version 1.5.9-RELEASE is based on Spring 4 and the SpringExtension is only available since Spring 5.

However, there is a solution since it's possible to use JUnit 5 and SpringExtension in Spring 4 by using spring-test-junit5. Just check the instructions for setting up the dependencies.

Question:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
                    properties = "logging.level.root=OFF")
public class MyTest {
         @Test
         public void test() {}
}

As a result of the simple test above, I'm getting much startup noise logged. This was not the case before upgrading to spring-boot-2.x. How can I prevent this noise?

Especially, my Intellij IDE logs those statements in red, which is even more confusing as the test itself passes...

Jul 31, 2018 1:55:57 PM org.springframework.boot.test.context.SpringBootTestContextBootstrapper buildDefaultMergedContextConfiguration
INFO: Neither @ContextConfiguration nor @ContextHierarchy found for test class [MyTest], using SpringBootContextLoader
Jul 31, 2018 1:55:57 PM org.springframework.test.context.support.AbstractContextLoader generateDefaultLocations
INFO: Could not detect default resource locations for test class [MyTest]: no resource found for suffixes {-context.xml, Context.groovy}.
Jul 31, 2018 1:55:57 PM org.springframework.test.context.support.AnnotationConfigContextLoaderUtils detectDefaultConfigurationClasses
INFO: Could not detect default configuration classes for test class [MyTest]: MyTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
Jul 31, 2018 1:55:57 PM org.springframework.boot.test.context.SpringBootTestContextBootstrapper getOrFindConfigurationClasses
INFO: Found @SpringBootConfiguration MyApp for test class MyTest
Jul 31, 2018 1:55:58 PM org.springframework.boot.test.context.SpringBootTestContextBootstrapper getDefaultTestExecutionListenerClassNames
INFO: Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener, org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener, org.springframework.security.test.context.support.ReactorContextTestExecutionListener]
Jul 31, 2018 1:55:58 PM org.springframework.boot.test.context.SpringBootTestContextBootstrapper getTestExecutionListeners
INFO: Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@1a4013, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@1b6e1eff, org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener@306f16f3, org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@702b8b12, org.springframework.test.context.support.DirtiesContextTestExecutionListener@22e357dc, org.springframework.test.context.transaction.TransactionalTestExecutionListener@49912c99, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@10163d6, org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener@2dde1bff, org.springframework.security.test.context.support.ReactorContextTestExecutionListener@15bbf42f, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener@550ee7e5, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener@5f9b2141, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener@247d8ae, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener@48974e45, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener@6a84a97d]

Maybe it has to do using log4j2?

 <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-log4j2</artifactId>
    </dependency>

Answer:

Edited

Create logback-test.xml in your test resource (\test\resources), Then put bellow snippet into it

<configuration>
    <include resource="org/springframework/boot/logging/logback/base.xml" />
    <logger name="org.springframework" level="OFF"/>
</configuration>

It prints default system INFOs, not startup noise logs. (As you wanted)

And dependency of test can be as follows

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

Question:

My Spring Boot application is started like this:

new SpringApplicationBuilder()
  .sources(ParentCtxConfig.class)
  .child(ChildFirstCtxConfig.class)
  .sibling(ChildSecondCtxConfig.class)
  .run(args);

Config classes are annotated with @SpringBootApplication. As a result, I have one root context and two child web contexts.

I want to write integration test and I would like to have same context hierarchy there. I want at least to test first child context (configured with ChildFirstCtxConfig.class) with his parent context (ParentCtxConfig.class). How can I achieve that?

Currently I autowired ApplicationContext in my test so I can inspect it. I have this class annotation in the test:

@RunWith(SpringRunner.class)    
@SpringBootTest(classes = { ParentCtxConfig.class, ChildFirstCtxConfig.class }, webEnvironment = WebEnvironment.RANDOM_PORT)

but that will produce single context and I want parent-child hierarchy. I assume that I should annotate my test with @ContextHierarchy annotation.

Changing my test annotation to this seems to work exactly the same like previous example:

@RunWith(SpringRunner.class)    
@ContextConfiguration(classes = { ParentCtxConfig.class, ChildFirstCtxConfig.class })
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)

But if I want to introduce @ContextHierarchy and have something like this:

@RunWith(SpringRunner.class)
@ContextHierarchy({
        @ContextConfiguration(name = "root", classes = ParentCtxConfig.class),
        @ContextConfiguration(name = "child", classes = ChildFirstCtxConfig.class)
})
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)

context is not started because of bean defined in parent context can't be found/autowired in child context. Setting loader = SpringBootContextLoader.class doesn't help.

Sample code: GitHub


Answer:

Update: This issue was fixed in Spring Boot 1.5.0 as mentioned by Peter Davis.

This is a limitation of @SpringBootTest. Move accurately, it's a limitation of SpringBootContextLoader. You could work around it by using a custom context loader that configures the parent context or with a ContextCustomizer the factory for which would need to be listed in spring.factories. Here's a rough example of the latter:

src/test/resources/META-INF/spring.factories:
org.springframework.test.context.ContextCustomizerFactory=\
com.alex.demo.ctx.HierarchyContextCustomizerFactory
src/test/java/com/alex/demo/ctx/HierarchyContextCustomizerFactory.java:
package com.alex.demo.ctx;

import java.util.List;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextCustomizerFactory;
import org.springframework.test.context.MergedContextConfiguration;

public class HierarchyContextCustomizerFactory implements ContextCustomizerFactory {

    @Override
    public ContextCustomizer createContextCustomizer(Class<?> testClass,
            List<ContextConfigurationAttributes> configAttributes) {
        return new ContextCustomizer() {

            @Override
            public void customizeContext(ConfigurableApplicationContext context,
                    MergedContextConfiguration mergedConfig) {
                if (mergedConfig.getParentApplicationContext() != null) {
                    context.setParent(mergedConfig.getParentApplicationContext());
                }

            }

        };
    }

}