2015-01-09 10 views
6

Ho un'applicazione Spring e in essa I non utilizzare uso configuraion xml, solo Condfig Java. Tutto è OK, ma quando provo a test ho avuto problemi con l'attivazione di awtowiring di componenti nei test. Quindi cerchiamo di iniziare ho un un'interfacciaCome creare l'istanza dell'interfaccia CrudRepository durante i test in primavera?

@Repository 
public interface ArticleRepository extends CrudRepository<Page, Long> { 
    Article findByLink(String name); 
    void delete(Page page); 
} 

E un componente/servizio

@Service 
public class ArticleServiceImpl implements ArticleService { 
    @Autowired 
    private ArticleRepository articleRepository; 
... 
} 

Non voglio usare le configurazioni XML così per i miei test cerco di testare ArticleServiceImpl utilizzando solo Configurazione Java. Quindi, ai fini di test che ho fatto:

@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() ho bisogno di mettere istanza di articleRepository(), ma si tratta di un'interfaccia. Come creare un nuovo oggetto con una nuova parola chiave? È possibile senza creare la classe di configurazione xml e abilitare Autowiring? Può awtowired essere abilitato quando si usano solo JavaConfigurations durante il test?

+0

No, non è così. Hai '@ Autowired 'quindi non hai bisogno di impostarlo. Devi mettere '@ EnableJpaRepositories' sulla tua classe di configurazione per consentire a Spring Data JPA di creare i bean per te. –

+0

Per ArticleServiceImpl ho anche Awtowire quindi non ho nemmeno bisogno di scrivere articleServiceImpl()? Ho ragione? Non riesco a capire come Spring sappia attivare Autowiring per i test. Errore nella creazione di bean con nome 'articleServiceImpl': Iniezione di dipendenze autowired non riuscite; l'eccezione annidata è org.springframework.beans.factory.BeanCreationException: Impossibile eseguire il campo autowire: private com.musala.repository.ArticleRepository – Xelian

+0

@ M.Deinum ha la risposta corretta. – Jaiwo99

risposta

10

Questo è quello che ho trovato è la configurazione minima per un test del controller a molla che richiede una configurazione di repository JPA autowired (utilizzando spring-boot 1.2 con spring 4.1.4.RELEASE, DbUnit 2.4.8 incorporato).

Il test viene eseguito su un DB HSQL incorporato che viene compilato automaticamente da un file di dati xml all'avvio del test.

La classe di test:

@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(); 
     } 
    } 
} 

Note:

  • annotazione @ContextConfiguration che comprende solo la TestController incorporato e la classe di configurazione RepoFactory4Test JPA.

  • L'annotazione @TestExecutionListeners è necessaria affinché le annotazioni successive @DatabaseSetup e @DatabaseTearDown hanno effetto

La classe di configurazione riferito:

@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; 
    } 
} 

L'UserRepository è una semplice interfaccia:

public interface UserRepository extends CrudRepository<EUser, Long> 
{ 
} 

The EUse r è un semplice @Entity classe annotata:

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

    ... 
} 

Il FillTestData.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<dataset> 
    <user id="1" 
      email="[email protected]" 
      ... 
    /> 
</dataset> 

Il DbClean.xml:

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

Grazie per questo articolo. Potete aiutarmi a comprendere il vero vantaggio della classe 'RepoFactory4Test'. – Sriram

+1

È uno dei due bean dichiarati nell'annotazione '@ ContextConfiguration' nella classe di test dell'unità. Ciò significa che la molla carica solo automagicamente questi due fagioli per la corsa del test. Il 'RepoFactory4Test' stesso fornisce alcuni ulteriori bean necessari per il funzionamento di JPA. Inoltre, definisce quale repository utilizzare (qui '@ EnableJpaRepositories') – Heri

+0

Grazie per i dettagli. Tuttavia, nel mio requisito, dovrei caricare i file '.sql' invece dei file' .xml' (come menzionato nell'esempio precedente) e cercare un modo per caricarli nella classe di test stessa, in questo caso 'Classe ControllerWithRepositoryTest'. A partire da ora, ho modificato il metodo 'dataSource()' dell'esempio precedente aggiungendo 'addScript()' che carica i sql. Ma, cercando una soluzione generica. Si prega di suggerire. – Sriram

0

Quello che dovete fare è:

  1. rimuovere @Repository da ArticleRepository

  2. aggiungere @EnableJpaRepositories a PagesTestConfiguration.java

    @Configuration 
    @ComponentScan(basePackages = {"com.example.core"}) // are you sure you wanna scan all the packages? 
    @EnableJapRepository(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; 
    } 
    } 
    
1

You cant utilizzare i repository nella classe di configurazione, perché da c Sulle classi di configurazione trova tutti i suoi repository usando @EnableJpaRepositories.

  1. Quindi modificare la configurazione Java per:
@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. Se si dispone di molte classi repository di implementazione quindi creare una classe separata come qui di seguito
@Service 
public class RepositoryImpl { 
    @Autowired 
    private UserRepositoryImpl userService; 
} 
  1. Nel controller da Autowire a RepositoryImpl e da lì è possibile accedere a tutte le classi di implementazione del repository.
@Autowired 
RepositoryImpl repository; 

Usage:

repository.getUserService().findUserByUserName (userName);

Rimuovere annotazione @Repository in ArticleRepository e ArticleServiceImpl dovrebbe implementare ArticleRepository non ArticleService.

2

Se si utilizza Primavera di avvio, è possibile semplificare leggermente questi approcci aggiungendo @SpringBootTest da caricare nel numero ApplicationContext. Questo ti permette di autowire nei tuoi repository di dati primaverili. Assicurarsi di aggiungere @RunWith(SpringRunner.class) quindi le annotazioni specifiche molle sono raccolti:

@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")); 
    } 
} 

Si può leggere di più su test in avvio primavera nella loro docs.

Problemi correlati