0

I use javax.validation with Spring. In my test (groovy) I explicitly create validator.

import javax.validation.Validation
import javax.validation.Validator
import javax.validation.ValidatorFactory

ValidatorFactory factory = Validation.buildDefaultValidatorFactory()
Validator validator = factory.getValidator()

when:
Set<ConstraintViolation<User>> constraints = validator.validate(entity)

My validator in java

public class EntityDynamicValidator implements ConstraintValidator<SomeConstraint, Entity> {

    private GroupService groupService;

    // This constructor is required, see the link bellow.
    public UserDynamicEnumValidator() {
    }

    public UserDynamicEnumValidator(final GroupService groupService) {
        this.groupService = groupService;
    }

    @Override
    public boolean isValid(final Entity entity, final ConstraintValidatorContext context) {
        Something something = groupService.findByValue(entity.getValue());
        // Validate all this stuff
    }
}

I need to pass a Spring service to the validator.

I have a default constructor because there is an issue Spring unit test issue with Validator

Yan Khonski
  • 12,225
  • 15
  • 76
  • 114
  • Does this answer your question? [Spring unit test issue with Validator](https://stackoverflow.com/questions/50104995/spring-unit-test-issue-with-validator) – Jacob van Lingen Feb 22 '21 at 15:29

2 Answers2

2

I also tried to solve this, however the tests are fully low level unit tests on my side and I wanted to avoid too much of a context. I couldn't even use your approach. The solution my side was to add a custom ConstraintValidatorBean into the mockmvc. That custom implementation could get a list of validator class Class objects and so if the factory tried to create a validator, I returned a Mockito.mock version of it instead of the real one and I could also look that up for expectation settings.

newhouse
  • 1,152
  • 1
  • 10
  • 27
  • Also makes sense, thanks for sharing. For unit tests without full context it's a reasonable approach. – Yan Khonski Aug 14 '19 at 14:04
  • can you please show some example code snippet ? – Amol Bais Dec 05 '20 at 12:03
  • 1
    @AmolBais sorry, but don't even remember in which codebase I did this :( But I think if you familiar with that class and the original approach described here, then my description should make sense :D – newhouse Dec 21 '20 at 11:43
1

Feel free to share your knowledge. This is how I solved this task.

I created a Spring component and it has a static field (GroupService which is initialized in constructor).

@Component // Spring component.
class ServiceHolderComponent {
    
    private static GroupService GROUP_SERVICE;

    @Autowired
    public ServiceHolderComponent(final GroupService groupService) {
        GROUP_SERVICE = Validate.notNull(groupService); //apache lib
    }

    public static GroupService getGroupService() {
        return GROUP_SERVICE;
    }
}

And now validator with default constructor.

public class EntityDynamicValidator implements ConstraintValidator<SomeConstraint, Entity> {

    private GroupService groupService;

    public UserDynamicEnumValidator() {
        this(ServiceHolderComponent.getGroupService());
    }

    public UserDynamicEnumValidator(final GroupService groupService) {
        this.groupService = groupService;
    }

    @Override
    public boolean isValid(final Entity entity, final ConstraintValidatorContext context) {
        Something something = groupService.findByValue(entity.getValue());
        // Validate all this stuff
    }
}

Apache library https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/Validate.html

import org.apache.commons.lang3.Validate;

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.11</version>
</dependency>

Yan Khonski
  • 12,225
  • 15
  • 76
  • 114