Domanda

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 ?

È stato utile?

Soluzione

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top