Developing Controller Layers by following TDD approach

Isolated testing of Controllers: -

Testing the Web Layer/Controllers: -
To do this we will use annotations: 
@WebMvcTest
@MockBean

Object:
MockMvc

Testing Controllers-with @WebMvcTest: -

Controller is dependent on Service Layer, if Service layer is not yet implemented, we can still test it by Mocking Service Layer.
• For our project, Customer microservice create a class called 'CustomerControllerTest' and annotate it with the below
– @RunWith(SpringRunner.class) : Helps in configuring Spring application context
– @WebMvcTest(CustomerController.class): Use this annotation for unit testing of MVC based application. Helps in configuring MVC infrastructure for testing without a
need for HTTP Servers.

Project Set-up:
– Add Maven dependencies to your Spring Boot project
• spring-boot-starter-test
• Database which is needed only while testing

Autowire MockMvc and Mock the beans needed in application context.
@WebMvcTest auto-configures MockMvc which offers a powerful way of easy testing MVC controllers without starting full HTTP server.

@Autowired
private MockMvc
@MockBean
private CustomerService service;

We also need the DTO’s and entity bean needed.
static CustomerDTO custDTO;
static Customer cust;

• Initialize the values for the variables.
– If initialization has to be done only once, do it in a public static method annotated using @BeforeClass
– If initialization needs to be done after every test method is executed then do it in a public void method annotated using @Before as shown below

@BeforeClass
public static void initialise() {
custDTO = new CustomerDTO();
cust = new Customer();
}

@Before
public void init() {
MockitoAnnotations.initMocks(this);
custDTO.setSsnId("123456789010");
custDTO.setAddress("#25, Millers Road, Bangalore");
custDTO.setDob("20-Mar-1981");
custDTO.setEmailId("Robert_Smith@gmail.com");
custDTO.setFirstName("Robert");
custDTO.setLastName("Smith");
cust = CustomerDTO.prepareEntity(custDTO);
}

Let us write the test case for the below user story which fetches the customer details whose phoneNo will be sent as path variable.
/customers/{phoneNo}

• Before we write the test let us set how our service layer should behave as we are not going to test against the actual service layer

String phoneNo = "9876536750";
custDTO.setPhoneNo("9876536750");

//Training the custService Mock object how to respond
when(custService.getCustomerDetails(phoneNo)).thenReturn(custDTO);

- Now let us make a call to our controller using mockMvc object

mockMvc.perform(get("/customers/" + phoneNo)).andExpect(status().isOk())
.andExpect(jsonPath("$.ssnId", is(custDTO.getSsnId())))
.andExpect(jsonPath("$.address", is(custDTO.getAddress())))
.andExpect(jsonPath("$.dob", is(custDTO.getDob())))
.andExpect(jsonPath("$.emailId", is(custDTO.getEmailId())))
.andExpect(jsonPath("$.firstName", is(custDTO.getFirstName())))
.andExpect(jsonPath("$.lastName", is(custDTO.getLastName())))
.andExpect(jsonPath("$.phoneNo", is(custDTO.getPhoneNo())));

verify(custService).getCustomerDetails(phoneNo);

– In the above code we are asking mockMvc to perform a get call to customers/{phoneNo} url and
expect the status as OK and also expect a jsonResponse whose values we are verifying against a
pre-defined object
– Replace get with the appropriate HTTP method name (in lowercase) if the call is via HTTP
PUT/POST/DELETE/