0

I'm quite new to spring boot and got a basic microservice put together (It accepts a Yelp url and scrapes the images for that restaurant). I thought it would be a good time to write some unit tests, but one thing I'm having trouble with is injecting mock classes into my tests for the servlet request/response.

The code I'm trying to test is quite simple, it looks like this. This is basically the entry point for my service, it accepts a JSON body, extracts a Yelp url from it, and thenYelpRequestController.makeYelpRequest() takes care of scraping the images and returning the image links in an ArrayList.

@RestController
public class RequestController {

    @PostMapping(value = "/")
    public ArrayList<String> index(@RequestBody String reqBodyString) {

        //my own function to parse the json string
        HashMap<String, String> requestBody = parseReqBodyString(reqBodyString);
        String yelpURL = requestBody.get("yelpURL");

        YelpRequestController yelpRequest = new YelpRequestController(yelpURL);
        ArrayList<String> yelpImgLinks = yelpRequest.makeYelpRequest();
        return yelpImgLinks;
    }

}

This is my unit test code. It basically creates a JSON string and sends a request to my RequestController and makes sure the response is okay. It passes right now, but I want the test to just test RequestController and nothing else. Currently it sends the url from the test through YelpRequestController and starts scraping images, which is what I don't want since I just want to isolate the RequestController in this test. I've been trying to mock the YelpRequestController class and return result, but I'm really having a lot of trouble.

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class RequestControllerTest {

    @Autowired
    private MockMvc mvc;

    @Test
    public void postRequestController() throws Exception {
        ObjectMapping jsonObject = new ObjectMapping();
        jsonObject.setYelpUrl("https://www.yelp.ca/biz/l-industrie-pizzeria-brooklyn");
        Gson gson = new Gson();
        String json = gson.toJson(jsonObject);
        mvc.perform(MockMvcRequestBuilders.post("/")
                .accept(MediaType.APPLICATION_JSON)
                .content(json))
                .andExpect(status().isOk());
    }
}

I've been reading about how to use Mockito, and understand how to mock another class and inject it into a class you are testing. But I'm really stuck trying to apply that here. Any help would be appreciated.

fap
  • 663
  • 1
  • 5
  • 14
girbic
  • 301
  • 3
  • 11
  • Make YelpRequestController a SPring bean. Autowire it in your RequestController. Pass the yelpURL to the makeYelpRequest() method rather than the constructor to make it a stateless object. Then your unit test can inject a mock YelpRequestController to the RequestController. Testability is all about dependency injection. If you create your dependencies yourself using `new`, you make it impossible to inject mock dependencies. – JB Nizet Nov 15 '17 at 07:45
  • Ah thank you, I'll look into doing that! – girbic Nov 15 '17 at 08:26

2 Answers2

0

Hi I hope my answer can help you a lot. Please see simple below,

@Autowired
private WebApplicationContext context;

private MockMvc mvc;

@Before
public void setUp() {
    this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}

Before you start to test you must to initialize the mvc. So you need to setUp your application ready before test. SoringBoot

 private MockMvc mockMvc;

@InjectMocks
private UserController userController;

@Before
public void init(){
    MockitoAnnotations.initMocks(this);
    mockMvc = MockMvcBuilders
            .standaloneSetup(userController)
            .addFilters(new CORSFilter())
            .build();
}

SpringMVC you need to inject your controller.

soyphea
  • 469
  • 5
  • 11
0

As pointed out in the comments you want to use dependency injection in your controller to make it testable in isolation. You can then use a WebMvcTest targeting this specific controller. In contrast to a SpringBootTest this doesn't load your full ApplicationContext.

This could look something like this:

@RestController
public class RequestController {

    @Autowired
    private YelpRequestController yelpRequest;

    @PostMapping(value = "/")
    public ArrayList<String> index(@RequestBody String reqBodyString) {

        //my own function to parse the json string
        HashMap<String, String> requestBody = parseReqBodyString(reqBodyString);
        String yelpURL = requestBody.get("yelpURL");

        ArrayList<String> yelpImgLinks = yelpRequest.makeYelpRequest(yelpURL);
        return yelpImgLinks;
    }

}

In your test class you annotate the class that you want to have mocked with @MockBean and Spring will automatically use it for @Autowired fields:

@RunWith(SpringRunner.class)
@WebMvcTest(RequestController.class)
@AutoConfigureMockMvc
public class RequestControllerTest {

    @Autowired
    private MockMvc mvc;
    @MockBean
    private YelpRequestController yelpRequest;

    @Test
    public void postRequestController() throws Exception {
        ObjectMapping jsonObject = new ObjectMapping();
        jsonObject.setYelpUrl("https://www.yelp.ca/biz/l-industrie-pizzeria-brooklyn");
        Gson gson = new Gson();
        String json = gson.toJson(jsonObject);
        mvc.perform(MockMvcRequestBuilders.post("/")
                .accept(MediaType.APPLICATION_JSON)
                .content(json))
                .andExpect(status().isOk());
    }
}
fap
  • 663
  • 1
  • 5
  • 14