配置 Spring 的 @DataJpaTest 以覆盖默认应用程序上下文 bean

Configuring Spring's @DataJpaTest that overrides default application context beans

我正在努力配置我的@DataJpaTest。我想利用@DataJpaTest 提供的自动配置的 spring 上下文,但我想覆盖其中的一些 bean。

这是我的主class:

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

    @Bean
    public CommandLineRunner commandLineRunner(BookInputPort bookInputPort) {
        return args -> {
            bookInputPort.addNewBook(new BookDto("ABC", "DEF"));
            bookInputPort.addNewBook(new BookDto("GHI", "JKL"));
            bookInputPort.addNewBook(new BookDto("MNO", "PRS"));
        };
    }

如您所见,我提供了依赖于某些服务的 CommandLineRunner 的实现。

我也有测试:

@DataJpaTest
public class BookRepositoryTest {

    public static final String TITLE = "For whom the bell tolls";
    public static final String AUTHOR = "Hemingway";

    @Autowired
    private BookRepository bookRepository;

    @Test
    public void testRepository() {
        Book save = bookRepository.save(new Book(TITLE, AUTHOR));
        assertEquals(TITLE, save.getTitle());
        assertEquals(AUTHOR, save.getAuthor());
    }
}

当我 运行 测试时出现以下错误:

No qualifying bean of type 'com.example.demo.domain.book.ports.BookInputPort' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

非常有道理!自动配置的测试仅为上下文的 'slice' 提供实现。显然缺少 BookInputPort 的实现。我在测试环境中不需要这个 commandLineRunner。我创建了一个不依赖于任何服务的 commandLineRunner。 我可以尝试通过添加到我的测试 class nested class :

来解决问题
@TestConfiguration
    static class BookRepositoryTestConfiguration {

        @Bean
        CommandLineRunner commandLineRunner() {
            return args -> {
            };
        }
    }

问题解决了。有点儿。如果我有更多这样的测试,我将不得不将这个嵌套的 class 复制粘贴到每个测试 class。这不是最佳解决方案。 我试图将其外部化为可以由 @Import 导入的配置 这是配置 class:

@Configuration
public class MyTestConfiguration {

    @Bean
    public CommandLineRunner commandLineRunner() {
        return args -> {
        };
    }
}

但随后应用程序失败并显示一条消息:

Invalid bean definition with name 'commandLineRunner' defined in com.example.demo.DemoApplication: Cannot register bean definition

我检查了这个错误,其他人在这种情况下建议:

@DataJpaTest(properties = "spring.main.allow-bean-definition-overriding=true")

我这样做了,我得到了:

No qualifying bean of type 'com.example.demo.domain.book.ports.BookInputPort' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

这与我开始遇到的问题完全相同。 我采取了所有这些步骤,发现自己回到了最开始的地方。

你知道如何解决这个问题吗?我没有模糊的想法或线索。

注释 @DataJpaTest 仅加载 Spring 启动应用程序的 JPA 部分,应用程序上下文可能不会加载,因为您有 @DataJpaTest 注释。尝试用 @SpringBootTest 替换 @DataJpaTest

根据Spring documentation

By default, tests annotated with @DataJpaTest will use an embedded in-memory database (replacing any explicit or usually auto-configured DataSource). The @AutoConfigureTestDatabase annotation can be used to override these settings. If you are looking to load your full application configuration, but use an embedded database, you should consider @SpringBootTest combined with @AutoConfigureTestDatabase rather than this annotation.

在Spring启动测试中class你可以这样做

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

    @Autowired
    private YourService yourService;

它确实加载了所有服务,我使用它非常好

如何在一个环境而不是另一个环境中加载特定实体

  1. 您可以在实体中使用 @Profile 注释。
  2. 在 entities/services 上放置 @Profile({"prod"}) 你不想加载测试 运行,并且
  3. @Profile({"prod", "test"}) 放在 entities/services 上,您希望在 testprod 环境中加载
  4. 然后 运行 testtest 配置文件。它不会加载不必要的 entities
  5. 您也可以在其他服务上添加 @Profile 注释。

@DataJpaTest一般从测试的当前包class开始扫描,向上扫描,直到找到@SpringBootConfiguration注解的class。

因此在存储库根包中创建 SpringBootConfiguration class 将仅创建在该包中定义的 bean。最重要的是,我们可以在该配置 class.

中添加我们的测试 class 所需的任何自定义测试 bean
@SpringBootConfiguration
@EnableAutoConfiguration
public class TestRepositoryConfig {

    @Bean
    public CommandLineRunner commandLineRunner() {
        return args -> {
        };
    }

    @Bean
    public BookInputPort bootInputPort(){
        return new BookInputPort();
    }

}