Как автоматически связать репозиторий в интеграционном тесте с Spring Boot?

Я пытаюсь написать интеграционный тест, но у меня проблемы с автоматическим подключением репозитория в тесте.

Я получаю это исключение: org.springframework.beans.BeanInstantiationException: не удалось создать экземпляр [org.observer.media.repository.ArticleRepository]: указанный класс является интерфейсом.

Изменить: я добавил PersistenceConfig.class с @EnableJpaRepositories, код ниже. Это приводит к исключению org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available

Я также попытался добавить Application.class в @SpringBootTest(classes = {} в попытке поймать все попытки, но это бросает Error creating bean with name 'articleRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class org.observer.media.model.Article

ScraperRunnerIntegrationTest (классы конфигурации содержат только компоненты классов домена):

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = {
        ApplicationConfig.class,
        PersistenceConfig.class,
        DeMorgenTestConfig.class,
        Article.class,
        ScraperRunner.class,
        DeMorgenWebsiteScraper.class,
        ArticleService.class,
        DeMorgenPageScraper.class,
        JsoupParser.class,
        DeMorgenArticleScraper.class,
        GenericArticleScraper.class,
        ImageMetaScraper.class,
        ArticlePrinter.class,
        ArticleRepository.class
})
public class ScraperRunnerIntegrationTest {

    private final static Article EXPECTED_ARTICLE_1 = anArticle().withHeadline("headline1").build();
    private final static Article EXPECTED_ARTICLE_2 = anArticle().withHeadline("headline2").build();

    @Autowired
    private ScraperRunner scraperRunner;
    @Autowired
    private DeMorgenWebsiteScraper deMorgenWebsiteScraper;

    @Autowired
    private ArticleRepository articleRepository;

    @Test
    public void run() {
        scraperRunner.run(deMorgenWebsiteScraper);

        assertThat(articleRepository.findAll()).containsOnly(EXPECTED_ARTICLE_1, EXPECTED_ARTICLE_2);
    }

Repository:

import org.observer.media.model.Article;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface ArticleRepository extends JpaRepository<Article, Long> {

    List<Article> findAll();

    Article findByHash(String hash);

    Article findByHeadline(String headline);

    List<Article> findArticleByHeadlineAndCompanyName(String headline, String companyName);

    @Query("SELECT CASE WHEN COUNT(a) > 0 THEN true ELSE false END FROM Article a WHERE a.hash = :hash")
    boolean existsByHash(@Param("hash") String hash);
}

PersistenceConfig.class:

package org.observer.media.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@Configuration
@EnableJpaRepositories("org.observer.media.repository") 
public class PersistenceConfig {
}

2 ответа

Вам нужно предоставить только те классы, которые помечены как @Configuration в @SpringBootTest,

Я изменил оригинальный пример отсюда, чтобы использовать @SpringBootTest аннотаций. Итак, работает следующая конфигурация:

@Configuration
@ComponentScan("hello")
public class AppConfig {

}

Обратите внимание @ComponentScan аннотаций. И тогда в моем тесте:

@RunWith(SpringRunner.class)
@SpringBootTest(classes={AppConfig.class})
public class CustomerRepositoryTests {
     @Autowired
     private CustomerRepository customerRepository;
}

И это сделало трюк. Вы можете попробовать сделать то же самое в вашем примере.

У меня было то же исключение org.springframework.beans.BeanInstantiationException: не удалось создать экземпляр [...]: указанный класс является интерфейсом в моем интеграционном тесте. Я решил без использования PersistenceConfig.class, но изменил только аннотации, используемые в моем классе интеграции, что было неправильно. Я использовал следующую аннотацию: @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE), потому что я не хотел использовать базу данных в памяти.

Ваш код может быть следующим:

@ComponentScan(basePackages = {"org.observer"})
@RunWith(SpringRunner.class)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@DataJpaTest
public class ScraperRunnerIntegrationTest {

    private final static Article EXPECTED_ARTICLE_1 = anArticle().withHeadline("headline1").build();
    private final static Article EXPECTED_ARTICLE_2 = anArticle().withHeadline("headline2").build();

    @Autowired
    private ScraperRunner scraperRunner;
    @Autowired
    private DeMorgenWebsiteScraper deMorgenWebsiteScraper;

    @Autowired
    private ArticleRepository articleRepository;

    @Test
    public void run() {
        scraperRunner.run(deMorgenWebsiteScraper);

        assertThat(articleRepository.findAll()).containsOnly(EXPECTED_ARTICLE_1, EXPECTED_ARTICLE_2);
    }

Может ты можешь попробовать @AutoConfigureDataJpa или @AutoConfigureXxx аннотации.

Другие вопросы по тегам