Java 如何在 Spring 测试期间创建 CrudRepository 接口的实例?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27856266/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 05:09:36  来源:igfitidea点击:

How to make instance of CrudRepository interface during testing in Spring?

javaxmlspringspring-mvcautowired

提问by Xelian

I have a Spring application and in it I do notuse xml configuration, only Java Config. Everything is OK, but when I try to testit I faced problems with enabling autowiring of components in the tests. So let's begin. I have an interface:

我有一个 Spring 应用程序,在其中我使用 xml 配置,只使用 Java 配置。一切正常,但是当我尝试对其进行测试时,我遇到了在测试中启用组件自动装配的问题。那么让我们开始吧。我有一个界面

@Repository
public interface ArticleRepository extends CrudRepository<Page, Long> {
    Article findByLink(String name);
    void delete(Page page);
}

And a component/service:

和一个组件/服务:

@Service
public class ArticleServiceImpl implements ArticleService {
    @Autowired
    private ArticleRepository articleRepository;
...
}

I don't want to use xml configurations so for my tests I try to test ArticleServiceImpl using only Java Configuration. So for the test purpose I made:

我不想使用 xml 配置,因此对于我的测试,我尝试仅使用 Java 配置来测试 ArticleServiceImpl。所以为了测试目的,我做了:

@Configuration
@ComponentScan(basePackages = {"com.example.core", "com.example.repository"})
public class PagesTestConfiguration {


@Bean
public ArticleRepository articleRepository() {
       // (1) What to return ?
}

@Bean
public ArticleServiceImpl articleServiceImpl() {
    ArticleServiceImpl articleServiceImpl = new ArticleServiceImpl();
    articleServiceImpl.setArticleRepository(articleRepository());
    return articleServiceImpl;
}

}

}

In articleServiceImpl() I need to put instance of articleRepository() but it is an interface. How to create new object with new keyword? Is it possible without creating xml configuration class and enable Autowiring? Can autowired be enabled when using only JavaConfigurations during testing?

articleServiceImpl()我需要把实例articleRepository(),但它是一个接口。如何使用 new 关键字创建新对象?是否可以不创建 xml 配置类并启用自动装配?在测试期间仅使用 JavaConfigurations 时是否可以启用自动装配?

采纳答案by Heri

This is what I have found is the minimal setup for a spring controller test which needs an autowired JPA repository configuration (using spring-boot 1.2 with embedded spring 4.1.4.RELEASE, DbUnit 2.4.8).

这是我发现的弹簧控制器测试的最小设置,它需要自动装配的 JPA 存储库配置(使用带有嵌入式 spring 4.1.4.RELEASE、DbUnit 2.4.8 的 spring-boot 1.2)。

The test runs against a embedded HSQL DB which is auto-populated by an xml data file on test start.

测试针对嵌入式 HSQL 数据库运行,该数据库在测试开始时由 xml 数据文件自动填充。

The test class:

测试类:

@RunWith( SpringJUnit4ClassRunner.class )
@ContextConfiguration( classes = { TestController.class,
                                   RepoFactory4Test.class } )
@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class,
                           DirtiesContextTestExecutionListener.class,
                           TransactionDbUnitTestExecutionListener.class } )
@DatabaseSetup( "classpath:FillTestData.xml" )
@DatabaseTearDown( "classpath:DbClean.xml" )
public class ControllerWithRepositoryTest
{
    @Autowired
    private TestController myClassUnderTest;

    @Test
    public void test()
    {
        Iterable<EUser> list = myClassUnderTest.findAll();

        if ( list == null || !list.iterator().hasNext() )
        {
            Assert.fail( "No users found" );
        }
        else
        {
            for ( EUser eUser : list )
            {
                System.out.println( "Found user: " + eUser );
            }
        }
    }

    @Component
    static class TestController
    {
        @Autowired
        private UserRepository myUserRepo;

        /**
         * @return
         */
        public Iterable<EUser> findAll()
        {
            return myUserRepo.findAll();
        }
    }
}

Notes:

笔记:

  • @ContextConfiguration annotation which only includes the embedded TestController and the JPA configuration class RepoFactory4Test.

  • The @TestExecutionListeners annotation is needed in order that the subsequent annotations @DatabaseSetup and @DatabaseTearDown have effect

  • @ContextConfiguration 注解只包含嵌入的 TestController 和 JPA 配置类 RepoFactory4Test。

  • 需要@TestExecutionListeners 注解,以便后续注解@DatabaseSetup 和@DatabaseTearDown 生效

The referenced configuration class:

引用的配置类:

@Configuration
@EnableJpaRepositories( basePackageClasses = UserRepository.class )
public class RepoFactory4Test
{
    @Bean
    public DataSource dataSource()
    {
        EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
        return builder.setType( EmbeddedDatabaseType.HSQL ).build();
    }

    @Bean
    public EntityManagerFactory entityManagerFactory()
    {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl( true );

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter( vendorAdapter );
        factory.setPackagesToScan( EUser.class.getPackage().getName() );
        factory.setDataSource( dataSource() );
        factory.afterPropertiesSet();

        return factory.getObject();
    }

    @Bean
    public PlatformTransactionManager transactionManager()
    {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory( entityManagerFactory() );
        return txManager;
    }
}

The UserRepository is a simple interface:

UserRepository 是一个简单的界面:

public interface UserRepository extends CrudRepository<EUser, Long>
{
}   

The EUser is a simple @Entity annotated class:

EUser 是一个简单的 @Entity 注释类:

@Entity
@Table(name = "user")
public class EUser
{
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Max( value=Integer.MAX_VALUE )
    private Long myId;

    @Column(name = "email")
    @Size(max=64)
    @NotNull
    private String myEmail;

    ...
}

The FillTestData.xml:

FillTestData.xml:

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
    <user id="1"
          email="[email protected]"
          ...
    />
</dataset>

The DbClean.xml:

DbClean.xml:

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
    <user />
</dataset>

回答by Jaiwo99

What you need to do is:

你需要做的是:

  1. remove @Repositoryfrom ArticleRepository

  2. add @EnableJpaRepositoriesto PagesTestConfiguration.java

    @Configuration
    @ComponentScan(basePackages = {"com.example.core"}) // are you sure you wanna scan all the packages?
    @EnableJpaRepositories(basePackageClasses = ArticleRepository.class) // assuming you have all the spring data repo in the same package.
    public class PagesTestConfiguration {
    
    @Bean
    public ArticleServiceImpl articleServiceImpl() {
        ArticleServiceImpl articleServiceImpl = new ArticleServiceImpl();
        return articleServiceImpl;
    }
    }
    
  1. 除去@RepositoryArticleRepository

  2. 添加@EnableJpaRepositoriesPagesTestConfiguration.java

    @Configuration
    @ComponentScan(basePackages = {"com.example.core"}) // are you sure you wanna scan all the packages?
    @EnableJpaRepositories(basePackageClasses = ArticleRepository.class) // assuming you have all the spring data repo in the same package.
    public class PagesTestConfiguration {
    
    @Bean
    public ArticleServiceImpl articleServiceImpl() {
        ArticleServiceImpl articleServiceImpl = new ArticleServiceImpl();
        return articleServiceImpl;
    }
    }
    

回答by sagar

You cant use repositories in your configuration class because from configuration classes it finds all its repositories using @EnableJpaRepositories.

您不能在配置类中使用存储库,因为它使用@EnableJpaRepositories 从配置类中找到所有存储库。

  1. So change your Java Configuration to:
  1. 因此,将您的 Java 配置更改为:
@Configuration
@EnableWebMvc
@EnableTransactionManagement
@ComponentScan("com.example")
@EnableJpaRepositories(basePackages={"com.example.jpa.repositories"})//Path of your CRUD repositories package
@PropertySource("classpath:application.properties")
public class JPAConfiguration {
  //Includes jpaProperties(), jpaVendorAdapter(), transactionManager(), entityManagerFactory(), localContainerEntityManagerFactoryBean()
  //and dataSource()  
}
@Configuration
@EnableWebMvc
@EnableTransactionManagement
@ComponentScan("com.example")
@EnableJpaRepositories(basePackages={"com.example.jpa.repositories"})//Path of your CRUD repositories package
@PropertySource("classpath:application.properties")
public class JPAConfiguration {
  //Includes jpaProperties(), jpaVendorAdapter(), transactionManager(), entityManagerFactory(), localContainerEntityManagerFactoryBean()
  //and dataSource()  
}
  1. If you have many repository implementation classes then create a separate class like below
  1. 如果您有许多存储库实现类,则创建一个单独的类,如下所示
@Service
public class RepositoryImpl {
   @Autowired
   private UserRepositoryImpl userService;
}
@Service
public class RepositoryImpl {
   @Autowired
   private UserRepositoryImpl userService;
}
  1. In your controller Autowire to RepositoryImpl and from there you can access all your repository implementation classes.
  1. 在您的控制器 Autowire 到 RepositoryImpl 中,您可以从那里访问所有存储库实现类。
@Autowired
RepositoryImpl repository;
@Autowired
RepositoryImpl repository;

Usage:

用法:

repository.getUserService().findUserByUserName(userName);

repository.getUserService().findUserByUserName(userName);

Remove @Repository Annotation in ArticleRepository and ArticleServiceImpl should implement ArticleRepository not ArticleService.

删除ArticleRepository 中的@Repository 注释,ArticleServiceImpl 应该实现ArticleRepository 而不是ArticleService。

回答by heez

If you're using Spring Boot, you can simplify these approaches a bit by adding @SpringBootTestto load in your ApplicationContext. This allows you to autowire in your spring-data repositories. Be sure to add @RunWith(SpringRunner.class)so the spring-specific annotations are picked up:

如果您使用的是 Spring Boot,则可以通过@SpringBootTestApplicationContext. 这允许您在 spring-data 存储库中自动装配。请务必添加,@RunWith(SpringRunner.class)以便拾取特定于弹簧的注释:

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

  @Autowired
  private UserRepository userRepository;

  @Test
  public void saveTest() {
    User user = new User("Tom");
    userRepository.save(user);
    Assert.assertNotNull(userRepository.findOne("Tom"));
  }
}

You can read more about testing in spring boot in their docs.

您可以在他们的文档中阅读有关在 spring 引导中进行测试的更多信息。