有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在Spring测试期间创建Crudepository接口实例?

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

@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的实例,但它是一个接口。如何使用new关键字创建新对象?是否可以不创建xml配置类并启用自动连接?测试期间仅使用JavaConfiguration时是否可以启用自动连线


共 (4) 个答案

  1. # 1 楼答案

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

    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()  
    }
    
    1. 如果您有许多存储库实现类,那么创建一个单独的类,如下所示
    @Service
    public class RepositoryImpl {
       @Autowired
       private UserRepositoryImpl userService;
    }
    
    1. 在控制器中,Autowire连接到RepositoryImpl,从那里可以访问所有存储库实现类
    @Autowired
    RepositoryImpl repository;
    

    用法:

    repository.getUserService().findUserByUserName(userName);

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

  2. # 2 楼答案

    如果您使用的是Spring Boot,那么可以通过在ApplicationContext中添加@SpringBootTest来简化这些方法。这允许您在spring数据存储库中自动连接。一定要添加@RunWith(SpringRunner.class),这样特定于spring的注释就会被选中:

    @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中阅读更多关于spring boot测试的内容

  3. # 3 楼答案

    你需要做的是:

    1. ArticleRepository中删除@Repository

    2. @EnableJpaRepositories添加到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;
      }
      }
      
  4. # 4 楼答案

    这就是我发现的spring控制器测试的最低设置,它需要一个自动连接的JPA存储库配置(使用spring boot 1.2和嵌入式spring 4.1.4.RELEASE,DbUnit 2.4.8)

    测试针对嵌入式HSQL数据库运行,该数据库在测试开始时由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>
    

    房间很干净。xml:

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