在执行JpaTest时无法找到@SpringBootConfiguration。

235

我试图运行一个简单的Junit测试来确保我的CrudRepositories确实正常工作。

我一直得到的错误是:

无法找到@SpringBootConfiguration,你需要在你的测试中使用@ContextConfiguration或@SpringBootTest(classes=...)。 java.lang.IllegalStateException

难道Spring Boot不能自己进行配置吗?

我的测试类:

@RunWith(SpringRunner.class)
@DataJpaTest
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class JpaTest {

@Autowired
private AccountRepository repository;

@After
public void clearDb(){
    repository.deleteAll();
}

 @Test
 public void createAccount(){
     long id = 12;
     Account u = new Account(id,"Tim Viz");
     repository.save(u);
      
     assertEquals(repository.findOne(id),u);
      
 }
  
  
 @Test
 public void findAccountByUsername(){
     long id = 12;
     String username = "Tim Viz";
     Account u = new Account(id,username);
     repository.save(u);
      
     assertEquals(repository.findByUsername(username),u);
      
 }
  

我的Spring Boot应用程序启动器:

@SpringBootApplication
@EnableJpaRepositories(basePackages = {"domain.repositories"})
@ComponentScan(basePackages = {"controllers","domain"})
@EnableWebMvc
@PropertySources(value    {@PropertySource("classpath:application.properties")})
    @EntityScan(basePackages={"domain"})
    public class Application extends SpringBootServletInitializer {
        public static void main(String[] args) {
            ApplicationContext ctx = SpringApplication.run(Application.class, args);         
 
        }
    }

我的存储库:

public interface AccountRepository extends CrudRepository<Account,Long> {

    public Account findByUsername(String username);

    }
}
16个回答

348

的确,Spring Boot 在很大程度上为自己设置了。您可能已经可以摆脱您发布的许多代码,特别是在 Application 中。

我希望您能够包含所有类的包名称,或者至少是 ApplicationJpaTest 的包名称。关于 @DataJpaTest 和其他一些注释的事情是,它们在当前包中查找 @SpringBootConfiguration 注释,如果在那里找不到它们,则遍历包层次结构直到找到它们。

例如,如果您的测试类的完全限定名称为 com.example.test.JpaTest,应用程序的名称为 com.example.Application,那么您的测试类将能够找到 @SpringBootApplication(及其中的 @SpringBootConfiguration)。

但是,如果应用程序位于包层次结构的不同分支中,例如 com.example.application.Application,则它将无法找到它。

示例

考虑下面的 Maven 项目:

my-test-project
  +--pom.xml
  +--src
    +--main
      +--com
        +--example
          +--Application.java
    +--test
      +--com
        +--example
          +--test
            +--JpaTest.java

接着是 Application.java 中的以下内容:

package com.example;

@SpringBootApplication
public class Application {

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

接下来是JpaTest.java的内容:

package com.example.test;

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

    @Test
    public void testDummy() {
    }
}

一切都应该正常工作。如果你在src/main/com/example文件夹下新建一个名为app的文件夹,并将你的Application.java文件放进去(并且更新文件中的package声明),运行测试会给你返回以下错误:

java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test


1
您好,感谢您提供解决方案。我正在使用Maven包设置,其中测试和应用程序代码有不同的包。 如果我理解正确,您的意思是,我必须将我的测试包直接指向应用程序类?然后它会找到SpringConfiguration吗? - Thomas Billet
如果您所说的“maven packet”指的是“module”,那么是的,包含测试类的模块必须依赖于“Application”所在的模块。但是,如果您指的是src/mainsrc/test,那么这些文件夹不属于包层次结构。也许您最好更新您的问题并附上屏幕截图或解释您的项目结构是什么样子的。 - Thomas Kåsene
3
+--测试 +--com +--示例 +--JpaTest.java 同样适用 - user674158
@ThomasBillet 你最终使用了哪种项目结构?根据我的发现,默认的结构是 src/main/javasrc/test/java - Bernie Lenz
@ThomasKåsene,在我的情况下,当我尝试为服务层编写测试时,与此问题相同的错误发生了,而且我的结构类似于https://softwareengineering.stackexchange.com/a/323746/214216。您能否建议一种编写此结构的单元测试的方法?非常感谢。 - Foolish
我恐怕这些信息太少了,而且在评论区里我可能无法给出足够好的答案。我建议您发布一个新问题,在其中展示您项目的结构、您想要实现的目标以及您遇到的确切错误信息。谢谢! - Thomas Kåsene

150

配置附加到应用程序类,因此以下设置将正确设置所有内容:

@SpringBootTest(classes = Application.class)

JHipster项目的示例在这里


1
这似乎是完美的解决方案。我不需要移动任何类或文件夹。 - Abhishek Aggarwal
即使应用程序类存在,我仍然遇到ClassNotFoundException异常。此外,您的链接不再有效。 - Praytic
@Praytic,感谢您提醒无效链接!我刚刚更新了它。至于ClassNotFound异常,请查看链接中的示例。 - mrts
2
这真是太完美了!更加精确地说,它解决了Thomas在他的帖子中提出的问题:“如果应用程序位于包层次结构的不同分支中,比如com.example.application.Application,它将找不到它。” - Shawn. L
1
只是为了确认一下,这里的 Application.class 是主类,对吗? - Sanal S

27

值得注意的是,检查一下你是否重构了标有@SpringBootApplication注释的主类的包名。如果是这种情况,测试用例应该在适当的包中,否则它将在旧包中寻找。我遇到过这种情况。


19

对我适用

上述测试类的包名已更改为与正常类的包名相同。

更改为如下


1
这绝对是答案。 - user1238097
就是这样!我解决了WebFluxTest类缺少包的问题...非常感谢! - Guy_g23

14

除了Thomas Kåsene所说的之外,你还可以添加

@SpringBootTest(classes=com.package.path.class)

通过测试注释来指定它应该在哪个类中查找其他类,如果您不想重新设计文件层次结构。这就是错误提示的含义:

Unable to find a @SpringBootConfiguration, you need to use 
@ContextConfiguration or @SpringBootTest(classes=...) ...

10
在我的情况下,应用程序和测试类之间的软件包不同。
package com.example.abc;
...
@SpringBootApplication
public class ProducerApplication {

package com.example.abc_etc;
...
@RunWith(SpringRunner.class)
@SpringBootTest
public class ProducerApplicationTest {

在让他们达成一致后,测试顺利运行。


8

我遇到了相同的问题,我通过在src/test/java文件夹的根包中添加一个带有SpringBootApplication注解的空类来解决它。

package org.enricogiurin.core;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class CoreTestConfiguration {}

1
没错,这正是我在寻找的。我有一个多模块的Spring项目,在其中我将测试移动到另一个模块中,但只有这个类在该模块中正确执行了测试。 - 0x52
同上 - 这是我见过的唯一适用于多模块 Gradle 项目的解决方案。 - Dan Tanner

7

在Spring Boot 1.4中提供的测试切片带来了面向特性的测试能力。

例如,

@JsonTest 提供了一个简单的Jackson环境来测试JSON序列化和反序列化。

@WebMvcTest 提供了一个模拟Web环境,可以指定要测试的控制器类并在测试中注入MockMvc。

@WebMvcTest(PostController.class)
public class PostControllerMvcTest{

    @Inject MockMvc mockMvc;

}

@DataJpaTest会为测试准备一个嵌入式数据库,并提供基本的JPA环境。
@RestClientTest为测试提供REST客户端环境,特别是RestTemplateBuilder等。
这些注释不与SpringBootTest组合使用,而是与一系列AutoconfigureXXX和@TypeExcludesFilter注释组合使用。
看看@DataJpaTest。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@BootstrapWith(SpringBootTestContextBootstrapper.class)
@OverrideAutoConfiguration(enabled = false)
@TypeExcludeFilters(DataJpaTypeExcludeFilter.class)
@Transactional
@AutoConfigureCache
@AutoConfigureDataJpa
@AutoConfigureTestDatabase
@AutoConfigureTestEntityManager
@ImportAutoConfiguration
public @interface DataJpaTest {}

您可以添加@AutoconfigureXXX注释来覆盖默认配置。
@AutoConfigureTestDatabase(replace=NONE)
@DataJpaTest
public class TestClass{
}

让我们来看一下您的问题,
  1. 请不要混合使用 @DataJpaTest@SpringBootTest,如上所述,@DataJpaTest 会按照其自己的方式构建配置(例如,默认情况下,它将尝试准备嵌入式 H2),从应用程序配置继承中。 @DataJpaTest 指定为测试片段
  2. 如果您想自定义 @DataJpaTest 的配置,请阅读 Spring.io 的此官方博客文章 (有点繁琐)。
  3. Application 中的配置按功能拆分成更小的配置,例如 WebConfigDataJpaConfig 等。一个完整功能的配置(混合了 web、数据、安全等)也会导致测试片段基于测试失败。请在这里查看我的示例中的测试样例

4
在我的情况下,请确保你的YourApplicationTests测试包名称与主包名字相同。

1
谢谢,我已经更改了应用程序的包名称,但测试类的包仍然过时。 - Hamza Abbas

2

请确保测试类位于您的主Spring Boot类的子包中


将此作为注释添加。 - A J

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接