Search code examples
springunit-testingspring-mvcmockitohibernate-annotations

how to do unit test validation annotations in spring


I have some annotation in a class such as

 public class ProductModel {
@Pattern(regexp="^(1|[1-9][0-9]*)$", message ="Quantity it should be number and greater than zero")
private String  quantity;

then in my controller

@Controller
public class Product Controller
private ProductService productService;
@PostMapping("/admin/product")
public String createProduct(@Valid @ModelAttribute("product") ProductModel productModel, BindingResult result)
{
    // add println for see the errors
    System.out.println("binding result: " + result);

    if (!result.hasErrors()) {
        productService.createProduct(productModel);
        return "redirect:/admin/products";
    } else {
        return "product";
    }
}

Then I am trying to do a test of createProduct from ProductController.

@RunWith(MockitoJUnitRunner.class)
public class ProductControllerTest {

@Autowired
private MockMvc mockMvc;

@Mock
ProductService productService;

@InjectMocks
ProductController productController;

@Mock
private BindingResult mockBindingResult;

@Before
public void setupTest() {
    MockitoAnnotations.initMocks(this);
    Mockito.when(mockBindingResult.hasErrors()).thenReturn(false);
}


@Test
public void  createProduct() throws Exception {

    productController = new ProductController(productService);      
   productController.createProduct(new ProductModel(), mockBindingResult);

Here I do not know how can I add values to the object productmodel and also how can I test the message output of "...number should be greater than zero". What I was trying to do it was create an object and then assert with values for making it fail or work such as assertEquals(hello,objectCreated.getName()); Any advice or help will be highly appreciated.


Solution

  • To validate bean annotations you must have the context in execution. You can do this with:

    @RunWith(SpringRunner.class)
    @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
    

    Then your tests will validate the annotations.

    However, if you just want to validate the annotation of model (without another business rules) you can use a validator:

    private static ValidatorFactory validatorFactory;
    private static Validator validator;
    
    @BeforeClass
    public static void createValidator() {
        validatorFactory = Validation.buildDefaultValidatorFactory();
        validator = validatorFactory.getValidator();
    }
    
    @AfterClass
    public static void close() {
        validatorFactory.close();
    }
    
    @Test
    public void shouldReturnViolation() {
        ProductModel productModel = new ProductModel();
        productModel.setQuantity("a crazy String");
    
        Set<ConstraintViolation<ProductModel>> violations = validator.validate(productModel);
    
        assertFalse(violations.isEmpty());
    }