Java 在Spring测试中如何制作Crudepository接口实例?
我有一个Spring应用程序,其中我不使用xml配置,只使用Java配置。一切正常,但当我尝试测试它时,我遇到了在测试中启用组件自动布线的问题。让我们开始吧。我有一个界面:Java 在Spring测试中如何制作Crudepository接口实例?,java,xml,spring,spring-mvc,autowired,Java,Xml,Spring,Spring Mvc,Autowired,我有一个Spring应用程序,其中我不使用xml配置,只使用Java配置。一切正常,但当我尝试测试它时,我遇到了在测试中启用组件自动布线的问题。让我们开始吧。我有一个界面: @Repository public interface ArticleRepository extends CrudRepository<Page, Long> { Article findByLink(String name); void delete(Page page); } 我不想使用
@Repository
public interface ArticleRepository extends CrudRepository<Page, Long> {
Article findByLink(String name);
void delete(Page page);
}
我不想使用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时是否可以启用自动连线?您需要做的是:
文章库中删除@Repository
@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;
}
}
您不能在配置类中使用存储库,因为它使用@EnableJpaRepositories从配置类中查找其所有存储库
删除ArticleRepository中的@Repository注释,ArticleServiceImpl应该实现ArticleRepository而不是ArticleService。我发现这是spring控制器测试的最低设置,它需要自动连线JPA存储库配置(使用spring boot 1.2和嵌入式spring 4.1.4.RELEASE,DbUnit 2.4.8) 测试针对嵌入式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();
}
}
}
UserRepository是一个简单的界面:
public interface UserRepository extends CrudRepository<EUser, Long>
{
}
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>
如果您使用的是Spring Boot,您可以通过添加
@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"));
}
}
您可以在他们的手册中阅读有关spring boot测试的更多信息。不,您不需要。您有@Autowired
,因此无需进行设置。您需要将@EnableJpaRepositories
放在您的配置类上,让Spring Data JPA为您创建bean。对于ArticleServiceImpl,我还有一个Awtowire,所以我不需要同时编写ArticleServiceImpl()?我说得对吗?我不明白Spring怎么知道为测试打开自动布线。创建名为“articleServiceImpl”的bean时出错:自动连线依赖项的注入失败;嵌套异常为org.springframework.beans.factory.BeanCreationException:无法自动连接字段:private com.musala.repository。ArticleRepository@M.Deinum答案正确。对于单元测试,根本不要使用真正的存储库。重构您的服务以使用构造函数注入并注入模拟存储库。这将使您的测试更加孤立,速度更快。感谢本文。您能帮助我理解repactory4test
类的真正好处吗?它是单元测试类中@ContextConfiguration
注释中声明的两个bean之一。这意味着spring仅在测试运行时自动加载这两个bean。repactory4test
本身提供了JPA工作所需的更多bean。除此之外,它还定义了要使用的存储库(此处为@EnableJpaRepositories
),感谢提供详细信息。但是,在我的需求中,我应该加载.sql
文件,而不是.xml
文件(如上面的示例所述),并寻找一种可以在测试类本身中加载它们的方法,在本例中是ControllerWithRepositoryTest
类。到目前为止,我已经修改了上面示例中的dataSource()
方法,添加了加载SQL的addScript()
。但是,寻找一个通用的解决方案。请建议。我用@WebMvcTest
运行它,不得不用@springbootest
和@AutoConfigureMockMvc
@Pedro替换它。当我发布这个答案时,我在springboot上1它看起来像是集成测试,在生产中你会遇到问题
@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;
}
}
public interface UserRepository extends CrudRepository<EUser, Long>
{
}
@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;
...
}
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<user id="1"
email="alice@test.org"
...
/>
</dataset>
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<user />
</dataset>
@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"));
}
}