spring-mvcspring-boot

Spring Boot: How to test a service in JUnit with @Validated annotation?


I'm trying to build a set of constraint validators for my Spring Boot application. I want to build some validation annotations like @NotNull. Btw: The validations should support validation groups.

So I have a simple item model with a validation annotation:

public class Item {
    @NotNull(groups=OnCreate.class) // Not Null on validation group 'OnCreate'
    private String mayNotBeNull;

    // Constructors and getter/setter stuff.
}

Then I wrapped the persistence logic using a validated service:

@Service
@Validated
public class MyService {
    public Item create(@Validated(OnCreate.class) Item item) {
        Item savedItem = repository.save(item);
        return savedItem;
    }
}

Now I want to test this service without starting a full blown MVC test (which would start all REST controllers and stuff I do not need).

I started to write my test:

@ContextConfiguration(classes = {
ItemRepository.class, MyService.class, LocalValidatorFactoryBean.class
})
@RunWith(SpringRunner.class)
public class PlantServiceTest {

  @MockBean
  private ItemRepository repository;

  @Autowired
  private MyService service;

  @Autowired
  private Validator validator;

  @Test
  public void shouldDetectValidationException() {
        // ... building an invalid item
        Item item = new Item();
        item.setMayNotBeNull(null); // <- This causes the validation exception.
        validator.validate(item, OnCreate.class);
  }

  @Test
  public void shouldAlsoDetectValidationException() {
        // ... building an invalid item
        Item item = new Item();
        item.setMayNotBeNull(null); // <- This should cause the validation exception.
        service.create(item); // <- No validation error. Service is not validating.
  }
  }

The method shouldThrowValidationException detects the validation error, because the field value in item is null.

The method shouldAlsoDetectValidationException does not detect the validation error.

I think I missed something when configuring the context. The service object is not extended by the validation logic.

How can I configure the test so that the autowired services are decorated with the validation logic provided by @Validated?


Solution

  • @Validated does not work as expected on Parameters. You have to use @Valid on the parameter and add the @Validated with the group on the method or class level.

    This way it works:

    @Service
    @Validated
    public class MyService {
    
        @Validated(OnCreate.class)
        public Item create(@Valid Item item) {
            ...
        }
    }
    

    Unfortunately I found no way to have the group on the parameter level.

    If you want to test your validation logic in a Spring Unit Test, then you must import the ValidationAutoConfiguration class via:

    @Import(ValidationAutoConfiguration.class)