Reputation: 2973
Test configuration class
@Configuration
@Import( value = GlobalCoreContext.class)
public class TestConfiguration {
@Bean
public Validator createValidatorFactory() {
return Validation.buildDefaultValidatorFactory().getValidator();
}
}
ValidatorClass
public final class LoginAttemptsExceededValidatorLoginId implements ConstraintValidator<LoginAttemptsExceeded, String> {
@Resource
private LoginDao loginDao;
private LoginAttemptsExceeded loginAttemptsExceeded;
@Override
public void initialize(final LoginAttemptsExceeded loginAttemptsExceeded) {
this.loginAttemptsExceeded = loginAttemptsExceeded;
}
/**
* Validation fails if the login attempts have exceeded the preset number.
* @param loginId
* @param constraintValidatorContext
* @return
*/
@Override
public boolean isValid(final String loginId, final ConstraintValidatorContext constraintValidatorContext) {
if(StringUtility.IsEmpty(loginId)) return false;
return !loginDao.findByLogin(loginId).isLoginAttemptsExceeded();
}
}
Unit Test class
@ContextConfiguration(classes = TestConfiguration.class )
public class LoginAttemptsExceededValidatorLoginIdTest extends AbstractTestNGSpringContextTests {
@Autowired
private Validator validator;
private PasswordChange passwordChange;
private LoginEntity loginEntity;
private static final String TEST_PASSWORD = "abcDEFG10";
private static final String TEST_LOGIN = "passwordChangeValidatorTestLogin";
@Resource
private LoginDao loginDao;
@BeforeMethod
public void setUp() throws Exception {
passwordChange = new PasswordChange(TEST_LOGIN, TEST_PASSWORD, "newPassword");
/**
* setup a Login record
*/
loginEntity = DataBuilder.createLogin();
loginEntity.setLogin(TEST_LOGIN);
loginEntity.setPasswordHash(encryptToBytes(TEST_PASSWORD));
loginEntity.setLoginAttempts(0);
loginDao.saveAndFlush(loginEntity);
}
@AfterMethod
public void tearDown() throws Exception {
// Remove the login record.
loginDao.delete(loginEntity);
loginDao.flush();
}
@Test
public void testIsValid() throws Exception {
Set<ConstraintViolation<PasswordChange>> constraintViolations = validator.validate(passwordChange);
assertEquals(constraintViolations.size(), 0, "When a valid username, password are supplied, the number of errors should be zero.");
}
}
GlobalCoreContext.java
@Configuration
@EnableJpaRepositories(basePackages = {"com.mrll.global.core.entities", "com.mrll.global.core.daos"})
@ComponentScan(basePackages = { "com.mrll.global.core.password", "com.mrll.global.core.util", "com.mrll.global.core.constraints" })
@EnableTransactionManagement
@Import({DataSourceContext.class, LiquibaseContext.class})
public class GlobalCoreContext {
private static Logger LOG = LoggerFactory.getLogger(GlobalCoreContext.class);
private static final String DATASOURCE_SCHEMA = "datasource.schema";
private static final String HIBERNATE_DIALECT = "hibernate.dialect";
private static final String HIBERNATE_SHOW_SQL = "hibernate.show_sql";
private static final String HIBERNATE_GEN_DDL = "hibernate.genddl";
private static final String HIBERNATE_CONN_CHARSET = "hibernate.connection.charSet";
private static final String ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";
@Resource
private org.springframework.core.env.Environment environment;
@Resource
DataSource dataSource;
@Bean
public EntityManager entityManger() {
try {
return entityManagerFactory().getObject().createEntityManager();
} catch (ClassNotFoundException e) {
throw new PersistenceException("unable to create entity manager", e);
}
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws ClassNotFoundException {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource);
entityManagerFactoryBean.setPackagesToScan(environment.getRequiredProperty(ENTITYMANAGER_PACKAGES_TO_SCAN));
entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter());
entityManagerFactoryBean.setJpaProperties(additionalProperties());
return entityManagerFactoryBean;
}
@Bean
public HibernateJpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setShowSql(Boolean.valueOf(environment.getRequiredProperty(HIBERNATE_SHOW_SQL)));
hibernateJpaVendorAdapter.setGenerateDdl(Boolean.valueOf(environment.getRequiredProperty(HIBERNATE_GEN_DDL)));
hibernateJpaVendorAdapter.setDatabasePlatform(environment.getRequiredProperty(HIBERNATE_DIALECT));
return hibernateJpaVendorAdapter;
}
/**
* add JPA properties, optionally adding default schema if profile's datasource is Oracle instance.
*
* @return Properties to add
*/
Properties additionalProperties() {
Properties properties = new Properties();
properties.put(HIBERNATE_CONN_CHARSET, environment.getRequiredProperty(HIBERNATE_CONN_CHARSET));
properties.put("hibernate.cache.use_second_level_cache", true);
// use this one for hibernate 4.x +
// properties.put("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory");
// use this one for hibernate 3.2.x +
// properties.put("hibernate.cache.region.factory_class", "net.sf.ehcache.hibernate.EhCacheRegionFactory");
// properties.put("hibernate.cache.use_query_cache", true);
// properties.put("hibernate.generate_statistics", true);
if (!"H2".equalsIgnoreCase(environment.getRequiredProperty(DataSourceContext.SPRING_PROFILES_ACTIVE))) {
properties.put("hibernate.default_schema", environment.getRequiredProperty(DATASOURCE_SCHEMA));
}
LOG.debug(String.format("properties=%s", properties));
return properties;
}
@Bean
public PlatformTransactionManager transactionManager() throws ClassNotFoundException {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
transactionManager.setJpaDialect(new HibernateJpaDialect());
return transactionManager;
}
@Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
@Bean
public static Constants getConstants() {
return Constants.getInstance();
}
}
For some reason, the loginDao
in isValid method inside the LoginAttemptsExceededValidatorLoginId
is null. It works well at runtime.
But during unit test the LoginDao
is not injected into the Validator even though the javax.validation.Validator
is being injected into the UnitTest.
What am I doing wrong ?
Upvotes: 1
Views: 3512
Reputation: 19119
My guess is that your problem lies here:
@Bean
public Validator createValidatorFactory() {
return Validation.buildDefaultValidatorFactory().getValidator();
}
This builds the default Validator, including the default ConstraintValidatorFactory which does not inject Spring beans. If you check the documentation you will find
By default, the LocalValidatorFactoryBean configures a SpringConstraintValidatorFactory that uses Spring to create ConstraintValidator instances. This allows your custom ConstraintValidators to benefit from dependency injection like any other Spring bean.
(see http://docs.spring.io/spring/docs/3.0.0.RC3/reference/html/ch05s07.html)
You have to make sure that your Validator uses the same constraint validator factory. Or why do you not inject LocalValidatorFactoryBean directly into the test? If I understand correctly GlobalCoreContext is where you programmatically configure your beans. Why not add there the LocalValidatorFactoryBean. However, I am not a Spring expert.
Upvotes: 7