J'ai une application Spring dans laquelle je _ {ne pas utilise la configuration xml, uniquement Java Condfig. Tout va bien, mais lorsque j'essaie de test cela, je rencontrais des problèmes pour activer le câblage des composants dans les tests. Commençons donc j'ai un interface
@Repository
public interface ArticleRepository extends CrudRepository<Page, Long> {
Article findByLink(String name);
void delete(Page page);
}
Et un composant/service
@Service
public class ArticleServiceImpl implements ArticleService {
@Autowired
private ArticleRepository articleRepository;
...
}
Je ne veux pas utiliser les configurations xml, donc pour mes tests, j'essaie de tester ArticleServiceImpl en utilisant uniquement la configuration Java. Donc, dans le but de tester, j'ai fait:
@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;
}
}
Dans articleServiceImpl _ (), je dois mettre une instance de articleRepository_ () mais c'est une interface. Comment créer un nouvel objet avec un nouveau mot clé? Est-il possible sans créer la classe de configuration XML et activer le transfert automatique? Peut-on activer awtowired lorsqu’on utilise uniquement JavaConfigurations lors des tests?
C’est ce que j’ai trouvé, c’est la configuration minimale d’un test de contrôleur de ressort nécessitant une configuration de référentiel JPA auto-câblé (avec spring-boot 1.2 avec un ressort intégré 4.1.4.RELEASE, DbUnit 2.4.8).
Le test s'exécute sur une base de données HSQL intégrée, qui est automatiquement renseignée par un fichier de données xml au début du test.
La classe de 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();
}
}
}
Remarques:
Annotation @ContextConfiguration qui inclut uniquement TestController intégré et la classe de configuration JPA RepoFactory4Test.
L'annotation @TestExecutionListeners est nécessaire pour que les annotations suivantes @DatabaseSetup et @DatabaseTearDown aient un effet.
La classe de configuration référencée:
@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;
}
}
UserRepository est une interface simple:
public interface UserRepository extends CrudRepository<EUser, Long>
{
}
EUser est une simple classe annotée @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;
...
}
Le FillTestData.xml:
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<user id="1"
email="[email protected]"
...
/>
</dataset>
Le fichier DbClean.xml:
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<user />
</dataset>
Si vous utilisez Spring Boot, vous pouvez simplifier un peu ces approches en ajoutant @SpringBootTest
à charger dans votre ApplicationContext
. Cela vous permet de connecter automatiquement vos référentiels de données de printemps. Assurez-vous d'ajouter @RunWith(SpringRunner.class)
pour que les annotations spécifiques au printemps soient relevées:
@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"));
}
}
Vous pouvez en savoir plus sur les tests dans Spring Boot dans leurs docs .
Vous ne pouvez pas utiliser de référentiels dans votre classe de configuration car, à partir des classes de configuration, il trouve tous ses référentiels à l'aide de @EnableJpaRepositories.
@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() }
@Service public class RepositoryImpl { @Autowired private UserRepositoryImpl userService; }
@Autowired RepositoryImpl repository;
Usage:
repository.getUserService (). findUserByUserName (userName);
Supprimez @Repository Annotation dans ArticleRepository et ArticleServiceImpl doit implémenter ArticleRepository et non ArticleService.
Ce que vous devez faire c'est:
supprimer @Repository
de ArticleRepository
ajouter @EnableJpaRepositories
à 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;
}
}