114

I am using Spring Data JPA and Spring Boot. The layout of the application is this

main
    +-- java
        +-- com/lapots/game/monolith
            +-- repository/relational
                +--RelationalPlayerRepository.java
            +-- web
                +--GrandJourneyMonolithApplication.java
                +-- config
                    +-- RelationalDBConfiguration.java
test
    +-- java
        +-- com/lapots/game/monolith
            +-- repository/relational
                +-- RelationalPlayerRepositoryTests.java
            +-- web
                +-- GrandJourneyMonolithApplicationTests.java

The repository for my object looks like this

public interface RelationalPlayerRepository extends JpaRepository<Player, Long> {
}

Additionally for the repositories I provided a configuration

@Configuration
@EnableJpaRepositories(basePackages = "com.lapots.game.monolith.repository.relational")
@EntityScan("com.lapots.game.monolith.domain")
public class RelationalDBConfiguration {
}

My main application looks like this

@SpringBootApplication
@ComponentScan("com.lapots.game.monolith")
public class GrandJourneyMonolithApplication {

    @Autowired
    private RelationalPlayerRepository relationalPlayerRepository;

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

    @Bean
    public CommandLineRunner initPlayers() {
        return (args) -> {
            Player p = new Player();
            p.setLevel(10);
            p.setName("Master1909");
            p.setClazz("warrior");

            relationalPlayerRepository.save(p);
        };
    }
}

Test for application looks like this

@RunWith(SpringRunner.class)
@SpringBootTest
public class GrandJourneyMonolithApplicationTests {

    @Test
    public void contextLoads() {
    }

}

The test for repository looks like this

@RunWith(SpringRunner.class)
@DataJpaTest
public class RelationalPlayerRepositoryTests {

    @Autowired
    private TestEntityManager entityManager;

    @Autowired
    private RelationalPlayerRepository repository;

    @Test
    public void testBasic() {
        Player expected = createPlayer("Master12", "warrior", 10);
        this.entityManager.persist(expected);
        List<Player> players = repository.findAll();
        assertThat(repository.findAll()).isNotEmpty();
        assertEquals(expected, players.get(0));
    }

    private Player createPlayer(String name, String clazz, int level) {
        Player p = new Player();
        p.setId(1L);
        p.setName(name);
        p.setClazz(clazz);
        p.setLevel(level);
        return p;
    }
}

But when I try to run the tests I get the error

Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.041 sec <<< FAILURE! - in com.lapots.game.monolith.repository.relational.RelationalPlayerRepositoryTests
initializationError(com.lapots.game.monolith.repository.relational.RelationalPlayerRepositoryTests)  Time elapsed: 0.006 sec  <<< ERROR!
java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test
at org.springframework.util.Assert.state(Assert.java:70)
at org.springframework.boot.test.context.SpringBootTestContextBootstrapper.getOrFindConfigurationClasses(SpringBootTestContextBootstrapper.java:202)
at org.springframework.boot.test.context.SpringBootTestContextBootstrapper.processMergedContextConfiguration(SpringBootTestContextBootstrapper.java:137)
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildMergedContextConfiguration(AbstractTestContextBootstrapper.java:409)
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildDefaultMergedContextConfiguration(AbstractTestContextBootstrapper.java:323)
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildMergedContextConfiguration(AbstractTestContextBootstrapper.java:277)
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildTestContext(AbstractTestContextBootstrapper.java:112)
at org.springframework.boot.test.context.SpringBootTestContextBootstrapper.buildTestContext(SpringBootTestContextBootstrapper.java:82)
at org.springframework.test.context.TestContextManager.<init>(TestContextManager.java:120)
at org.springframework.test.context.TestContextManager.<init>(TestContextManager.java:105)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTestContextManager(SpringJUnit4ClassRunner.java:152)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.<init>(SpringJUnit4ClassRunner.java:143)
at org.springframework.test.context.junit4.SpringRunner.<init>(SpringRunner.java:49)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:104)
at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:86)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:33)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:283)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:173)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:128)
at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:203)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:155)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)

What is the problem? Domain Player loooks like this

@Data
@Entity
@Table(schema = "app", name = "players")
public class Player {
    @Id
    @GeneratedValue
    private Long id;

    @Transient
    Set<Player> comrades;

    @Column(unique = true)
    private String name;

    private int level;

    @Column(name = "class")
    private String clazz;
}
Anish B.
  • 9,111
  • 3
  • 21
  • 41
lapots
  • 12,553
  • 32
  • 121
  • 242

10 Answers10

247

src/test/java packages and src/main/java packages should match. I had same issue where

  • my src/main/java packages were starting with com.comp.example but
  • src/test/java packages were starting with com.sample.example

Because of this spring boot application was not able to pickup the configuration of the application, which it picks up from @SpringBootApplication class. So test case should fall under the same packages where @SpringBootApplication in src/main/java is written.

Saurabh Parmar
  • 2,471
  • 2
  • 7
  • 4
  • 2
    I am using Spring Boot with a simple REST controller. Not using any JPA and was getting same error as specified in the title here for my controller test. Also I am using a custom configuration for my Spring boot app. This answer (Oct 19 '18 at 7:20 Saurabh Parmar) helped. The root cause for me too was the package name. The package for my test under the src/test/java was not matching the one under the src/main/java. Once I fixed that it worked. – VC2019 Apr 26 '21 at 19:29
  • I had a typo in my test package name – Heiner May 03 '21 at 15:27
  • 3
    I completely forgot to add the package name. That did the trick – Renato Gama Jun 28 '21 at 13:59
  • To avoid the need of matching the test classes packages with production code ones, just specify in the SpringBootTest annotation the class to be used to load the app context like this @SpringBootTest(classes = Application.class) – Emiliano Schiano Oct 31 '21 at 17:26
  • 1
    Yes that was exactly my problem. However you can overcome this issue like this: @SpringBootTest( classes = MyTest.MyTestConfiguration.class ) public class MyTest { // your tests here @Configuration @ComponentScan( basePackages = { "com.comp.example", "com.sample.example" } ) static class MyTestConfiguration {} } – antonrud Jul 26 '22 at 21:25
  • This solution solved for me! Thanks Saurabh Parmar! – Eddy Francisco Aug 01 '22 at 19:56
  • My main class is in package `com.xx.app`, but my test class is in `com.xx.sample`, so it will not find the main class if it scans from bottom to top: 1. `com.xx.sample` 2. `com.xx` 3. `com`. It won't reach `com.xx.app` – ZhengguanLi Aug 04 '23 at 01:16
35

When Spring Boot starts, it scans the classpath from top to bottom of the project to find the config file. Your config is under another files and that is a reason of the problem. Move you config higher up to the monolith package and everything will be fine.

Simeon Leyzerzon
  • 18,658
  • 9
  • 54
  • 82
Yuriy Tsarkov
  • 2,461
  • 2
  • 14
  • 28
  • 1
    but shouldn't it possible to specify the configuration class in the test? – lapots Nov 25 '17 at 18:22
  • also I moved `configuration` class and it didn't help – lapots Nov 25 '17 at 19:55
  • 2
    The answer above should be correct. Structure your application as [suggested in the documentation](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using-boot-structuring-your-code) and the test should be able to search up to find the configuration. You might be having additional problems due to annotations that are disabling auto-configuration. Try also removing `@EnableJpaRepositories`, `@EntityScan` and `@ComponentScan`. – Phil Webb Nov 30 '17 at 19:42
27

@SpringBootTest has a parameter named classes. It accepts an array of classes for configuration. Add the class for the config file to it, for example:

@SpringBootTest(classes={com.lapots.game.monolith.web.GrandJourneyMonolithApplication.class})
Dmitriy Popov
  • 2,150
  • 3
  • 25
  • 34
downeyt
  • 1,206
  • 2
  • 12
  • 23
  • 1
    this worked for me: `@SpringBootTest(classes = App.class, webEnvironment = WebEnvironment.DEFINED_PORT)` - see https://stackoverflow.com/questions/43468754/valuelocal-server-port-not-working-in-spring-boot-1-5 – Sasha Bond Feb 23 '21 at 19:47
15

The Test src/test/java files should also follow the same directory structure as in src/main/java.

enter image description here

pankaj pundir
  • 377
  • 3
  • 6
4

In my case this was due to some [move|copy/paste] of classes. For some, the package clause was either [not updated correctly|not present] and the changes were not picked up but the IDE.

Anyways, review your project packaging.

Joel Mata
  • 456
  • 4
  • 8
3

if your project has no testable code in it and you have the default test block in the spring boot default test class

@SpringBootTest

class DemoApplicationTests {
    @Test
    void contextLoads() {
    }
}

delete the test annotation and the the contextLoads() method. to this

@SpringBootTest
class DemoApplicationTests {
}
mumbasa
  • 632
  • 7
  • 11
2

For me it worked by adding the path to the main class as below

@SpringBootTest(classes = {com.ghimire.bookApi.SpringBookApiPracticeApplication.class})
LinFelix
  • 1,026
  • 1
  • 13
  • 23
0

I was able to resolve this problem only after including in the @SpringBootTest classes both the context configuration class and the application class.

Apostolos
  • 10,033
  • 5
  • 24
  • 39
Nava Polak Onik
  • 1,509
  • 2
  • 13
  • 17
0

Delete the file module-info.java. This worked for me.

ggorlen
  • 44,755
  • 7
  • 76
  • 106
pwipo
  • 463
  • 3
  • 7
0

Although not a direct answer to the OP Question, I was able to solve my own experience of the same error message (as the Title of this Question) in IntelliJ IDEA:

Some part of the "Maven Dance"™️ {mvn clean compile, [IntelliJ] Reload All Maven Projects} solved it for me.

cellepo
  • 4,001
  • 2
  • 38
  • 57