JSR 303 bean validation unit testing with Mockito and Autowiring
junit4, mockito, unit-testing, validation
Solution
To achieve this I created custom ConstraintValidatorFactory to provide my custom ConstraintValidator.
Assume we have the following:
- SomeValidation - Bean Validation constraint annotation
- SomeValidationValidator - Bean Validation constraint validator with @Autowired dependencies. It contains two constructors: default and the one that takes dependencies
Now you can create a test SomeValidationValidatorTest that implements ConstraintValidatorFactory and is run with MockitoJUnitRunner.class:
@RunWith(MockitoJUnitRunner.class)
public class SomeValidationValidatorTest implements ConstraintValidatorFactory {
@Mock
private MyDependency myDependencyMock;
}
You must implement getInstance method from ConstraintValidatorFactory:
@Override
public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) {
if (key == SomeValidationValidator.class) {
return (T) new SomeValidationValidator(myDependencyMock);
}
throw new IllegalArgumentException("expecting SomeValidationValidator!");
}
Having this you can configure the Validator:
@Before
public void setUp() throws Exception {
// see https://docs.jboss.org/hibernate/validator/5.2/reference/en-US/html/chapter-bootstrapping.html#_constraintvalidatorfactory
Configuration<?> config = Validation.byDefaultProvider().configure();
config.constraintValidatorFactory(this);
ValidatorFactory factory = config.buildValidatorFactory();
validator = factory.getValidator();
}
In the end create some test:
@Test
public void someTest1() {
// arrange
Bean bean = new Bean();
Mockito.when(myDependencyMock.isValid(null)).thenReturn(true);
// act
Set<ConstraintViolation<Bean>> constraintViolations = validator.validate(bean);
// assert
Assert.assertTrue(constraintViolations.isEmpty());
Mockito.verify(myDependencyMock).isValid(null);
}
The above solution is not perfect but I assume it gives you the idea of using custom ConstraintValidatorFactory to solve the problem.
Problem
I want to junit test my validator class but my validator class has @autowired service classes. How do I inject these dependencies using Mocikto? I am going to call the validator using below line of code. ``` Set<ConstraintViolation<MyDomainPOJOObject>> constraintViolationsFromJavaRules = validator.validate(myDomainPOJOObject, Default.class); ``` Problem is I am not instantiating validator class myself. It's the JSR 303 framework which truely calls the validator's isValid method(). Another thing is I don't want to use spring Autowiring and use the `@Mock and @InjectMock` annotations. Any examples or ideas? I was able to get it working by having below line of code ``` @Override public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) { if (key == com.nitin.validation.UpperCaseValidator.class) { return (T)upperCasevalidator; } //throw new IllegalArgumentException("expecting SomeValidationValidator!"); return new ConstraintValidatorFactoryImpl().getInstance(key); } ```