Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make instance of CrudRepository interface during testing in Spring?

I have a Spring application and in it I do not use xml configuration, only Java Config. Everything is OK, but when I try to test it I faced problems with enabling autowiring of components in the tests. So let's begin. I have an interface:

@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:

@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?

like image 357
Xelian Avatar asked Jan 09 '15 08:01

Xelian


People also ask

Which annotation is used over class for testing CrudRepository?

The @TestExecutionListeners annotation is needed in order that the subsequent annotations @DatabaseSetup and @DatabaseTearDown have effect.

Is CrudRepository an interface?

Overview. CrudRepository is a Spring Data interface for generic CRUD operations on a repository of a specific type. It provides several methods out of the box for interacting with a database.

How do you exclude certain interfaces from instantiation as repository?

To exclude an interface extending Repository from being instantiated as a repository instance it can either be annotate it with @NoRepositoryBean or moved out side of the configured base-package .

How do I configure CrudRepository?

To use CrudRepository we have to create our interface and extend CrudRepository . We need not to implement our interface, its implementation will be created automatically at runtime. Find some of CrudRepository methods. <S extends T> S save(S entity) : Saves and updates the current entity and returns that entity.


1 Answers

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="[email protected]"
          ...
    />
</dataset>

The DbClean.xml:

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
    <user />
</dataset>
like image 132
Heri Avatar answered Sep 27 '22 16:09

Heri