I have a Spring application (not Spring Boot) where I use Spring Data JPA and annotation based Java configuration. I am trying to unit test (JUnit 4) a repository fragment where I created custom save methods, but I cannot properly load the required context and beans to run the tests:
[main] INFO org.springframework.test.context.support.DefaultTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.test.context.event.EventPublishingTestExecutionListener]
[main] INFO org.springframework.test.context.support.DefaultTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@87f383f, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@4eb7f003, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@eafc191, org.springframework.test.context.support.DirtiesContextTestExecutionListener@612fc6eb, org.springframework.test.context.transaction.TransactionalTestExecutionListener@1060b431, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@612679d6, org.springframework.test.context.event.EventPublishingTestExecutionListener@11758f2a]
[main] INFO org.springframework.data.repository.config.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
[main] INFO org.springframework.data.repository.config.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 96ms. Found 3 JPA repository interfaces.
[main] INFO org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean 'repositoryConfig' of type [com.example.app.config.RepositoryConfig$$EnhancerBySpringCGLIB$$4ffca507] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
[main] ERROR org.springframework.test.context.TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@eafc191] to prepare test instance [com.example.app.test.tests.UserDaoTests@37313c65]
java.lang.NoClassDefFoundError: org.springframework.beans.FatalBeanException
How should I load the application context appropriately?
UserDaoTests
@ActiveProfiles("dev")
@ContextConfiguration(loader=AnnotationConfigContextLoader.class, classes= {RepositoryConfig.class})
@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
public class UserDaoTests {
private UserRepository userRepository;
@Autowired
private DataSource dataSource;
@Autowired
public void setUserRepository (UserRepository userRepository) {
this.userRepository = userRepository;
}
private User user1 = new User("user", "userpass", true);
@Before
public void init() {
System.out.println("Before running tests: init");
JdbcTemplate jdbc = new JdbcTemplate(dataSource);
jdbc.execute("delete from sec.authorities");
jdbc.execute("delete from sec.users");
}
@Test
public void testExists () {
userRepository.save(user1);
System.out.println("Users created, test exists");
assertTrue("User should exist", userRepository.existsByUsername("user"));
assertFalse("User should not exist", userRepository.existsByUsername("abcdefghj"));
}
}
RepositoryConfig
@Configuration
@ComponentScan("com.example.app.dao")
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = {
"com.example.app.dao"
}, entityManagerFactoryRef = "entityManagerFactory",
transactionManagerRef = "transactionManager")
public class RepositoryConfig {
@Profile("production")
@Bean(name = "dataSource")
public DataSource dataSource() {
JndiDataSourceLookup lookup = new JndiDataSourceLookup();
return lookup.getDataSource("java:jboss/datasources/postgresqlDS");
}
@Profile("dev")
@Bean(name = "dataSource")
public DataSource jdbcDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setConnectionProperties(jdbcProperties().toString());
return dataSource();
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean emf
= new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource());
emf.setPackagesToScan(new String[] { "com.example.app.dao" });
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
emf.setJpaVendorAdapter(vendorAdapter);
emf.setJpaProperties(hibernateProperties());
return emf;
}
private final Properties hibernateProperties() {
//...
}
private final Properties jdbcProperties() {
Properties jdbcProperties = new Properties();
jdbcProperties.setProperty("driverClassName", "${jdbc.driver}");
jdbcProperties.setProperty("url", "${jdbc.url}");
jdbcProperties.setProperty("username", "${jdbc.username}");
jdbcProperties.setProperty("password", "${jdbc.password}");
return jdbcProperties;
}
@Bean
public TransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
transactionManager.setDataSource(dataSource());
return transactionManager;
}
@Bean
public PersistenceExceptionTranslationPostProcessor exceptiontranslator() {
return new PersistenceExceptionTranslationPostProcessor();
}
}
UserRepository
public interface UserRepository extends CustomizedSave<User>, CrudRepository<User, Long> {
Optional<User> findByUsername(String username);
Boolean existsByUsername(String username);
}
CustomizedSaveImpl
@Repository
public class CustomizedSaveImpl implements CustomizedSave<User>{
@Autowired
private BCryptPasswordEncoder passwordEncoder;
@PersistenceContext
EntityManager em;
public CustomizedSaveImpl() {
System.out.println("successfully loaded users DAO");
}
public User save (User user) {
//...
}
}