How to make instance of CrudRepository interface during testing in Spring?
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).
The test runs against a embedded HSQL DB which is auto-populated by an xml data file on test start.
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
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:
public interface UserRepository extends CrudRepository<EUser, Long>{}
The EUser is a simple @Entity annotated class:
@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:
<?xml version="1.0" encoding="UTF-8"?><dataset> <user id="1" email="alice@test.org" ... /></dataset>
The DbClean.xml:
<?xml version="1.0" encoding="UTF-8"?><dataset> <user /></dataset>
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:
@RunWith(SpringRunner.class)@SpringBootTestpublic 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.
You cant use repositories in your configuration class because from configuration classes it finds all its repositories using @EnableJpaRepositories.
- So change your Java Configuration to:
@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
@Servicepublic class RepositoryImpl { @Autowired private UserRepositoryImpl userService;}
- In your controller Autowire to RepositoryImpl and from there you can access all your repository implementation classes.
@AutowiredRepositoryImpl repository;
Usage:
repository.getUserService().findUserByUserName(userName);
Remove @Repository Annotation in ArticleRepository and ArticleServiceImpl should implement ArticleRepository not ArticleService.