简体   繁体   中英

How to mock Spring 5 WebClient in spring boot API testing

I have a spring boot API which internally calls two 3rd party API's using Spring WebClient. I need to test my API end to end by mocking the two API calls. How can I create a MockWebServer to mock the two API calls in my DAOImpl class.

I tried configuring a MockWebServer to mock the WebClient, but its not working.

My Controller

@Autowired
private DemoDao dao;

@RequestMapping(value = "/webClient/testing", produces = { "application/json"}, method = RequestMethod.GET)
public ResponseEntity<String> webClientNonBlockingClient(@RequestHeader(value = "name_id", required = false) String nameId)
  {
    HttpStatus httpStatus = HttpStatus.OK;
    String userId = dao.getUserId(nameId);
    boolean userCheck = dao.checkUserAccess(nameId, userId);
    if (userCheck)
    {
      message = "check success";
    }
    else
    {
      message = "check failed";
      httpStatus = HttpStatus.UNAUTHORIZED;
    }
    return new ResponseEntity<>(message, httpStatus);
  }

DAO impl class

@Repository
public class DemoDAOImpl
{

  @Autowired
  private WebClientFactory webClientFactory;

  public String getUserId(String nameId)
  {
    UserProfile profile = new UserProfile();
    Mono<UserProfile> response = null;
    try
    {
      String url = "/user/"+nameId+"/profile"
      WebClient client = webClientFactory.getWebClient();
      response = client.get().uri(builder -> 
      builder.path(url).build()).retrieve().bodyToMono(UserProfile.class);
      profile = response.block();
    }
    catch (WebClientResponseException e)
    {
      LOG.error("ResponseException {}", e);
    }
    return profile.getUserId();
  }

  public boolean userCheck(String nameId, String userId)
  {
    Mono<UserAccessResponse> result = null;
    try
    {
      WebClient client = webClientFactory.getWebClient();
      String url = "/user/"+nameId+"/check"
      result = client.get().uri(builder -> builder.path(url).queryParam("userId", userId).build())
          .retrieve().bodyToMono(UserAccessResponse.class);
      return result.block().isStatus();
    }
    catch (WebClientResponseException e)
    {
      LOG.error("APIexception {}", e);
    }
  }

webClient configuration class

@Configuration
public class WebClientFactory
{

  private String baseUrl = "https://abcd.com/v1/";

  private String apikey = "123456";

  public WebClientFactory()
  {
    // Default constructor
  }

  @Bean
  @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
  public WebClient getWebClient()
  {
    return WebClient
        .builder()
        .baseUrl(baseUrl)
        .defaultHeader(HttpHeaders.CONTENT_TYPE, 
 MediaType.APPLICATION_JSON_VALUE)
        .defaultHeader("apikey", apikey)
      .build();
  }  
}
}

I tried mocking with below test class, but its not working as expected. i am unable to configure how to mock the 2 external api calls.

Test class

@RunWith(SpringRunner.class)
@WebAppConfiguration()
@TestPropertySource("classpath:dev-manifest.yml")
@ContextConfiguration(classes = Application.class)
@SpringBootTest
public class WebClientMockTesting
{

  private static final Logger logger = LoggerFactory.getLogger(WebClientMockTesting.class);

  private static final String REQUEST_URI = "/webClient/testing";
  private static final String HEADER_KEY = "name_id";
  private static final String MOCK_USER_ID = "mockTest";

  private final MockWebServer mockWebServer = new MockWebServer();

  @Autowired
  private WebClientFactory webClientFactory;

  @Autowired
  private WebClient webClient;

  private MockMvc mockMvc;

  @Autowired
  private WebApplicationContext webApplicationContext;

  /**
   * build web application context
   */
  @Before
  public void setup()
  {
    try
    {
      mockWebServer.play(8084);
    }
    catch (IOException e)
    {
      e.printStackTrace();
    }
    webClient = webClientFactory.getWebClient();
    webClient = WebClient.create(mockWebServer.getUrl("/").toString());
    this.mockMvc = webAppContextSetup(webApplicationContext).build();
  }

  @AfterEach
  void tearDown() throws IOException
  {
    mockWebServer.shutdown();
  }

  /**
   * Success scenario - GetFutureProjectedIncomeRIC
   */
  @Test
  public void testGetId()
  {
    try
    {
      mockWebServer.enqueue(
          new MockResponse()
                  .setResponseCode(200)
                  .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                  .setBody("{\"y\": \"value for y\", \"z\": 789}")
  );

      mockMvc.perform(get(REQUEST_URI).contentType(contentType).header(HEADER_KEY, MOCK_USER_ID))
          .andExpect(status().isOk());
    }
    catch (Exception e)
    {
      logger.error("test failed due to - {}", e.getStackTrace());
    }
  }

What exactly doesn't work? In mock web server you create a queue of responses sent back one by one in the order you adding them. In you code you add one response using

mockWebServer.enqueue(

if you need to do 3 calls from your app you should call enqueue 3 times.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM