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
How to make instance of CrudRepository interface during testing in Spring?
提问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:
你需要做的是:
remove
@Repository
fromArticleRepository
add
@EnableJpaRepositories
toPagesTestConfiguration.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; } }
除去
@Repository
从ArticleRepository
添加
@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; } }
回答by sagar
You cant use repositories in your configuration class because from configuration classes it finds all its repositories using @EnableJpaRepositories.
您不能在配置类中使用存储库,因为它使用@EnableJpaRepositories 从配置类中找到所有存储库。
- So change your Java Configuration to:
- 因此,将您的 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() }
- If you have many repository implementation classes then create a separate class like below
- 如果您有许多存储库实现类,则创建一个单独的类,如下所示
@Service public class RepositoryImpl { @Autowired private UserRepositoryImpl userService; }
@Service public class RepositoryImpl { @Autowired private UserRepositoryImpl userService; }
- In your controller Autowire to RepositoryImpl and from there you can access all your repository implementation classes.
- 在您的控制器 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 @SpringBootTest
to 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,则可以通过@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"));
}
}
You can read more about testing in spring boot in their docs.
您可以在他们的文档中阅读有关在 spring 引导中进行测试的更多信息。