0
votes

I have the program which displays the fields with names and the user needs to enter them. How can I test this?

User.java - class for user.

public class User {
    @NotEmpty
    private String firstName;

    @NotEmpty
    private String lastName;

public String getAllInfo() {
        return this.firstName + '\n' + this.lastName;
    }

//getters and setters

}

Store.java - my controller class.

public class Store {

...

@PostMapping("/cart/index")
    public String getInfo(@Valid final User user, final Model model) {
        Store.LOGGER.info("{}", user.getAllInfo());
        return "cart/index";
    }

@GetMapping(value = "cart/index")
    public String index(final Model model) {
        model.addAttribute("user", new User());
        return "cart/index";
    }

...
}

My junit test now fails and i'm getting the following message.

null
null
MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /cart/index
       Parameters = {}
          Headers = {Accept=[application/json]}

Handler:
             Type = app.vlad.store.Store
           Method = public java.lang.String app.vlad.store.Store.getInfo(app.vlad.user.User,org.springframework.ui.Model)

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = cart/index
             View = null
        Attribute = user
            value = app.vlad.user.User@248deced
           errors = []

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = {}
     Content type = null
             Body = 
    Forwarded URL = cart/index
   Redirected URL = null
          Cookies = []

java.lang.AssertionError: No value at JSON path "$.firstName", exception: json can not be null or empty

My test:

StoreTest.java

public class StoreTest {

    @Autowired
    MockMvc        mockMvc;

    @Mock
    private User   user;
    @Mock
    private Model  model;
    @Mock
    Store          store;

    @Autowired
    List<Products> products;

    @Before
    public void setup() {

        MockitoAnnotations.initMocks(this);
        final Store store = new Store(this.products);

        this.mockMvc = MockMvcBuilders.standaloneSetup(store).build();

    }
@Test
    public void testGetInfo() throws Exception {
        this.user.setFirstName("Ivan");
        this.user.setLastName("Ivanov");

        this.mockMvc
                .perform(MockMvcRequestBuilders.post("/cart/index")
                        .accept(MediaType.APPLICATION_JSON))
                .andDo(MockMvcResultHandlers.print())
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.firstName").value("Ivan"))
                .andExpect(MockMvcResultMatchers.jsonPath("$.lastName").value("Ivanov"));

    }
}
4
There are few ways for it, did you try something? - Lemmy

4 Answers

1
votes

The best way would be using SpringBootTest. This will start a Spring Boot application and you can then use something like RestAssured to call the API.

This website details all of the setup: http://www.masterspringboot.com/getting-started/testing-spring-boot/testing-spring-boot-with-rest-assured

1
votes

A simple solution to just test your class which has validations i.e. User class in above example with simple Junit may be

In your Junit class

//The Class in spring which validates the annotations e.g @Notnull
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

 //Declare the field of this class into your test class
 private LocalValidatorFactoryBean localValidatorFactory;

//Initialize the bean in Before test here I have used Hibernate Validator Implementation 
@Before
public void setup() {
    localValidatorFactory = new LocalValidatorFactoryBean();
    localValidatorFactory.setProviderClass(HibernateValidator.class);
    localValidatorFactory.afterPropertiesSet();
}

//Inside your test method use the Local validator
@Test
  public void testNullValidationError() {
        final User user = new Use ();
        user.setfirstName(null);
        user.setLastName(null);
        Set<ConstraintViolation<User>> constraintViolations =      localValidatorFactory.validate(user);
        Assert.assertTrue("Your error message", constraintViolations.notNull == null);
    } 

If you wish to test your API then you can better use Spring MockMvc

which is meant for that purpose. Some sample helpful code for the same You need to run your using

@RunWith(SpringJUnit4ClassRunner.class)

        //You have to inject the Spring MockMvc which can redirect the request URL to your method.

        @Inject
        MockMvc mvc;
    //Intialize the Mock server before test execution
    @Before 
    public void init(){
    MockMvcBuilders.standaloneSetup(new Store()).build(); //I am assuming Store is ur controller Class

    inside ur test 
    you can do something lik e

    MvcResult result = mvc.perform(post(url).
                    contentType(MediaType.APPLICATION_JSON).
                    content(toJson(registration))).
                    andExpect(status().isBadRequest()).
                    andExpect(content().contentType(MediaType.APPLICATION_JSON)).
                    andReturn();
    }
1
votes

Try this

@Autowired
private MockMvc mvc;

@Test
public void testGetInfo() {
    @Mock
    private User user;
    @Mock
    private Model model;
    @Mock
    private Store store;

    user.setFirstName("Test");
    user.setLastName("User");

    mvc.perform( MockMvcRequestBuilders
            .post("/cart/index")
            .accept(MediaType.APPLICATION_JSON))
            .andDo(print())
            .andExpect(status().isOk())
            .andExpect(MockMvcResultMatchers.jsonPath("$.firstName").value("Test"))
            .andExpect(MockMvcResultMatchers.jsonPath("$.lastName").value("User"));

}
1
votes

you can use @WebMvcTest to achieve this.

Look at the following example :

@RunWith(SpringRunner.class)
@WebMvcTest(YourController.class)
public class YourControllerTest {

    @Autowired MockMvc mvc;
    @MockBean EmployeeService employeeService;

    @Test
    public void testPostMapping() throws Exception {

        YourRequestModel request = createRequestForPostMethod();

        mvc.perform(post("/cart/index")


      .contentType(MediaType.APPLICATION_JSON)
                .content(toJson(request)))
                .andExpect(status().isOk())
.andExpect(jsonPath("$.firstName", is("yourExpectedOutput")));
        }

In Above code you can mock your dependent service using @MockBean. The test will perform post on your custom Employee object and validate the response

You can add headers, authorization while calling perform

Assuming you using JSON as media type, you can write toJson() method using any json library to convert Employee object into Json string format

private String toJson(YourRequestModel yrm) {...}

If you are using XML, then you can do the same for XML

You can validate the response using expectations in chained way with $.firstName, or whatever contract you have.

Let me know if you have any doubt.