60

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.
  • 7,985
  • 3
  • 16
  • 39
lapots
  • 11,059
  • 29
  • 106
  • 218
  • 1
    What happens if you annotate `RelationalPlayerRepositoryTests` with `@ContextConfiguration(classes = GrandJourneyMonolithApplication.class)`? – Sam Brannen Nov 26 '17 at 16:27
  • @SamBrannen it shows error that it `failed to replace DataSource with embedded` – lapots Nov 26 '17 at 17:55

7 Answers7

139

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
  • 1,391
  • 2
  • 6
  • 4
  • 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
  • 1
    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
25

When the Spring Boot starts, it scans the classpath from the top to the 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 upper to the monolith package and everything gonna be fine.

Dmitriy Popov
  • 1,814
  • 2
  • 19
  • 28
Yuriy Tsarkov
  • 2,231
  • 1
  • 14
  • 27
  • 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
15

@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
  • 1,814
  • 2
  • 19
  • 28
downeyt
  • 1,036
  • 2
  • 10
  • 23
  • 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
4

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

enter image description here

pankaj pundir
  • 147
  • 1
  • 4
2

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
  • 350
  • 1
  • 6
0

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

Nava Polak Onik
  • 1,329
  • 2
  • 11
  • 17
0

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

ggorlen
  • 33,459
  • 6
  • 59
  • 67
pwipo
  • 367
  • 2
  • 7