9

I have the following unit test:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {EqualblogApplication.class})
@WebAppConfiguration
@TestPropertySource("classpath:application-test.properties")
public class PostServiceTest {
  // ...

  @Test(expected = ConstraintViolationException.class)
  public void testInvalidTitle() {
       postService.save(new Post());  // no title
  }
}

The code for save in PostService is:

public Post save(@Valid Post post) {
    return postRepository.save(post);
}

The Post class is marked with @NotNull in most fields.

The problem is: no validation exception is thrown.

However, this happens only in testing. Using the application normally runs the validation and throws the exception.

Note: I would like to do it automatically (on save) and not by manually validating and then saving (since it's more realistic).

Luís Soares
  • 5,726
  • 4
  • 39
  • 66
  • 1
    dupplicated. See : http://stackoverflow.com/questions/13745848/how-to-test-valid – J.Mengelle Jun 28 '16 at 16:08
  • that solution only gives a programmatic approach.: validator.validateProperty(object, propertyName) I wanted an implicit validation on save – Luís Soares Jun 28 '16 at 16:18
  • The solution with `@Inject MockMvc mvc;` look good to me ? – J.Mengelle Jun 29 '16 at 08:05
  • Well.. not bad.. but it assumes an MVC controller layer. What if I want to use @Valid to protect the layer below? (the service/business layer).... in that case there is no MVC involved. Additionally, it's not as transparent as doing just a "save" and expecting a validation (just like running the app). – Luís Soares Jun 29 '16 at 09:47
  • 1
    well, i'm not sure about which componant in spring is responsible to process the validation. You could test the validation itself, but you may need an integration test (full deploy) for testing if the @valid is processed. For testing the validation result, see exemple §101.2.1.5 at http://www.jmdoudoux.fr/java/dej/chap-validation_donnees.htm – J.Mengelle Jun 29 '16 at 12:40
  • 1
    You may want to dig about `MethodValidationPostProcessor` – J.Mengelle Jun 29 '16 at 12:48
  • great! it seems promising. thanks! – Luís Soares Jun 29 '16 at 16:03

3 Answers3

12

This solution works with Spring 5. It should work with Spring 4 as well. (I've tested it on Spring 5 and SpringBoot 2.0.0).

There are three things that have to be there:

  1. in the test class, provide a bean for method validation (PostServiceTest in your example)

Like this:

@TestConfiguration
static class TestContextConfiguration {
   @Bean
   public MethodValidationPostProcessor bean() {
      return new MethodValidationPostProcessor();
   }
}
  1. in the class that has @Valid annotations on method, you also need to annotate it with @Validated (org.springframework.validation.annotation.Validated) on the class level!

Like this:

@Validated
class PostService {
   public Post save(@Valid Post post) {
       return postRepository.save(post);
   }
}
  1. You have to have a Bean Validation 1.1 provider (such as Hibernate Validator 5.x) in the classpath. The actual provider will be autodetected by Spring and automatically adapted.

More details in MethodValidationPostProcessor documentation

Hope that helps

Vlad Dinulescu
  • 1,173
  • 1
  • 14
  • 24
1

This is how I did it by loading ValidationAutoConfiguration.class into context:

@SpringBootTest
@ContextConfiguration(classes = { MyComponent.class, ValidationAutoConfiguration.class
public class MyComponentValidationTest {
  
  @Autowired
  private MyComponent myComponent;

  @Test
  void myValidationTest() {
    String input = ...;
    // static import from org.assertj.core.api.Assertions
    assertThatThrownBy(() -> myComponent.myValidatedMethod(input))
      .isInstanceOf(ConstraintViolationException.class)
      .hasMessageContaining("my error message");
  }

}

And MyComponent class:

@Component
@Validated
public class MyComponent {


  public void myValidatedMethod(@Size(min = 1, max = 30) String input) {
    // method body
  }

)
Nima Ajdari
  • 2,754
  • 2
  • 14
  • 18
0

Add below dependency in your pom and your junit with mockmvc will work.

<dependency>
  <groupId>org.glassfish</groupId>
  <artifactId>javax.el</artifactId>
  <version>3.0.1-b08</version>
</dependency>
Shakti
  • 1
  • 1