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

时间:2015-01-09 08:11:25

标签: java xml spring spring-mvc autowired

我有一个Spring应用程序,其中使用xml配置,只使用Java Condfig。一切都很好,但是当我尝试测试时,我遇到了在测试中启用组件的问题。所以我们开始有一个 界面

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

组件/服务

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

我不想使用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;
}

}

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

4 个答案:

答案 0 :(得分:11)

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

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

测试类:

@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();
        }
    }
}

注意:

  • @ContextConfiguration注释,仅包含嵌入式TestController和JPA配置类RepoFactory4Test。

  • 需要@TestExecutionListeners注释才能使后续注释@DatabaseSetup和@DatabaseTearDown生效

引用的配置类:

@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;
    }
}

UserRepository是一个简单的界面:

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

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;

    ...
}

FillTestData.xml:

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
    <user id="1"
          email="alice@test.org"
          ...
    />
</dataset>

DbClean.xml:

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

答案 1 :(得分:7)

如果您正在使用Spring Boot,则可以通过添加@SpringBootTest加载ApplicationContext来简化这些方法。这允许您在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"));
  }
}

您可以在docs中了解有关春季启动测试的更多信息。

答案 2 :(得分:1)

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

  1. 因此,请将Java配置更改为:
  2. @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. 如果您有许多存储库实现类,则创建一个单独的类,如下面的
    2. @Service
      public class RepositoryImpl {
         @Autowired
         private UserRepositoryImpl userService;
      }
      
      1. 在您的控制器Autowire to RepositoryImpl中,您可以从那里访问所有存储库实现类。
      2. @Autowired
        RepositoryImpl repository;
        

        用法:

          

        repository.getUserService()findUserByUserName(用户名);

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

答案 3 :(得分:0)

您需要做的是:

  1. @Repository

  2. 中移除ArticleRepository
  3. @EnableJpaRepositories添加到PagesTestConfiguration.java

    @Configuration
    @ComponentScan(basePackages = {"com.example.core"}) // are you sure you wanna scan all the packages?
    @EnableJapRepository(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;
    }
    }