为了账号安全,请及时绑定邮箱和手机立即绑定

使用 Mockito 在客户端测试 POST 请求

使用 Mockito 在客户端测试 POST 请求

摇曳的蔷薇 2022-08-17 12:15:54
我想测试应该向“服务器”发送post请求的post方法(因此我想模拟来自服务器的响应并检查响应)。另外,我想测试响应是否在正文中包含http状态OK。问题:我应该如何使用 mockito?客户端中的“我的帖子”方法(客户端):public class Client{        public static void sendUser(){        String url = "http://localhost:8080/user/add";        HttpHeaders requestHeaders = new HttpHeaders();        requestHeaders.setContentType(MediaType.APPLICATION_JSON);        requestHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));        User test = new User();        test.setName("test");        test.setEmail("a@hotmail.com");        test.setScore(205);        RestTemplate restTemplate = new RestTemplate();        HttpEntity<User> request = new HttpEntity<>(test);        ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, request, String.class);        if(response.getStatusCode() == HttpStatus.OK){            System.out.println("user response: OK");        }      }  }另一个模块(服务器端)中的我的控制器:@RestController@RequestMapping("/user")public class UserController{    @Autowired    private UserRepository userRepository;    @PostMapping("/add")    public ResponseEntity addUserToDb(@RequestBody User user) throws Exception    {        userRepository.save(user);        return ResponseEntity.ok(HttpStatus.OK);    }测试:    @RunWith(SpringRunner.class)@ActiveProfiles("test")@SpringBootTest(classes = Client.class)@AutoConfigureMockMvcpublic class ClientTest{    private MockRestServiceServer mockServer;    @Autowired    private RestTemplate restTemplate;     @Autowired    private MockMvc mockMvc;    @Before    public void configureRestMVC()    {        mockServer =                MockRestServiceServer.createServer(restTemplate);    }    @Test    public void testRquestUserAddObject() throws Exception    {        User user = new User("test", "mail", 2255);        Gson gson = new Gson();        String json = gson.toJson(user );        mockServer.expect(once(), requestTo("http://localhost:8080/user/add")).andRespond(withSuccess());}
查看完整描述

2 回答

?
慕尼黑5688855

TA贡献1848条经验 获得超2个赞

根据您的客户端类,希望提出以下更改建议,以使其更易于测试:


    //  class

    public class Client {


        /*** restTemplate unique instance for every unique HTTP server. ***/

        @Autowired

        RestTemplate restTemplate;


        public ResponseEntity<String> sendUser() {


        String url = "http://localhost:8080/user/add";


        HttpHeaders requestHeaders = new HttpHeaders();

        requestHeaders.setContentType(MediaType.APPLICATION_JSON);

        requestHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));


        User test = new User();

        test.setName("test");

        test.setEmail("a@hotmail.com");

        test.setScore(205);


        HttpEntity<User> request = new HttpEntity<>(test);


        ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, request, String.class);


        if(response.getStatusCode() == HttpStatus.OK){

            System.out.println("user response: OK");

        }

        return response;

      }

  }

然后对于上面的我们朱尼特作为:


@RunWith(MockitoJUnitRunner.class)

public class ClientTest {


  private String RESULT = "Assert result";


  @Mock

  private RestTemplate restTemplate;


  @InjectMocks

  private Client client;


  /**

   * any setting needed before load of test class

   */

  @Before

  public void setUp() {

    // not needed as of now

  }


  // testing an exception scenario

  @Test(expected = RestClientException.class)

  public void testSendUserForExceptionScenario() throws RestClientException {


    doThrow(RestClientException.class).when(restTemplate)

        .exchange(anyString(), any(HttpMethod.class), any(HttpEntity.class), any(Class.class));

    // expect RestClientException

    client.sendUser();

  }


  @Test

  public void testSendUserForValidScenario() throws RestClientException {


    // creating expected response

    User user= new User("name", "mail", 6609); 

    Gson gson = new Gson(); 

    String json = gson.toJson(user); 

    doReturn(new ResponseEntity<String>(json, HttpStatus.OK)).when(restTemplate)

        .exchange(anyString(), any(HttpMethod.class), any(HttpEntity.class), any(Class.class));

    // expect proper response

    ResponseEntity<String> response =

        (ResponseEntity<String>) client.sendUser();

    assertEquals(this.RESULT, HttpStatus.OK, response.getStatusCode());

  }

}

基本上在您的功能中,我们正在做:sendResponse()


// we are getting URL , creating requestHeader

// finally creating HttpEntity<User> request 

// and then passing them restTemplate.exchange 

// and then restTemplate is doing its job to make a HTPP connection and getresponse...

// and then we are prinnting the response... somestuff 

因此,在相应的测试中,我们还应该只测试函数正在执行的操作,因为连接正在被照顾,并且您没有覆盖任何工作,因此我们不应该为相同的事情做任何事情......而只是测试我们的代码/逻辑。restTemplaterestTemplate


最后,为了确保导入看起来像:


可以肯定的是,进口会像这样:


import org.springframework.http.HttpEntity; 

import org.springframework.http.HttpHeaders; 

import org.springframework.http.HttpMethod; 

import org.springframework.http.HttpStatus; 

import org.springframework.http.MediaType; 

import org.springframework.http.ResponseEntity; 

import org.springframework.web.client.RestTemplate;

希望这有帮助。


查看完整回答
反对 回复 2022-08-17
?
largeQ

TA贡献2039条经验 获得超8个赞

首先是完整代码(说明如下):


import static org.springframework.test.web.client.ExpectedCount.manyTimes;

import static org.springframework.test.web.client.ExpectedCount.once;

import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;

import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;

import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


@RunWith(SpringRunner.class)

@ActiveProfiles("test")

@SpringBootTest

@AutoConfigureMockMvc

public class MyTestClass {


MockRestServiceServer mockServer;


    @Autowired

    private RestTemplate restTemplate;  //create a bean somewhere. It will be injected here. 


    @Autowired

    private MockMvc mockMvc;


    @Before

    public void configureRestMVC(){

        mockServer =

                MockRestServiceServer.createServer(restTemplate);

    }


    @Test

    public void test0() throws Exception {

        //this is where you would mock the call to endpoint and and response

        mockServer.expect(once(), requestTo("www.example.com/endpoint1"))

        .andRespond(withSuccess());

    ... 

    //here you will actually make a call to your controller. If the service class is making a post call to another endpoint outside, that you just mocked in above statement.

    this.mockMvc.perform(post("www.example2.com/example2endpoint")

                .content(asJsonString(new YouCustomObjectThatYouWantToPost))

                .contentType(MediaType.APPLICATION_JSON))

        .andDo(print()).andExpect(status().isOk())

        .andExpect(content().json(matchResponseAgainstThisObject()));

   }

您需要使用注释。背后的目的是根本不启动服务器,而只测试该层下面的层,其中Spring处理传入的HTTP请求并将其传递给您的控制器。这样,几乎使用完整的堆栈,并且您的代码将被调用,就像它处理真正的HTTP请求一样,但没有启动服务器的成本。为此,我们将使用Spring的MockMvc,我们可以通过使用测试类上的注释来要求为我们注入它。@AutoConfigureMockMvc@AutoConfigureMockMvc


private MockRestServiceServer mockServer;

MockRestServiceServer是客户端REST测试的主要入口点。用于涉及直接或间接使用 RestTemplate 的测试。提供一种方法来设置将通过 RestTemplate 执行的预期请求,以及要发送回的模拟响应,从而消除了对实际服务器的需求。


mockServer.expect(once(), requestTo("www.example.com/endpoint1"))

    .andRespond(withSuccess());

这是您将设置模拟外部调用的地方。以及设置期望。


this.mockMvc.perform(post("www.example2.com/example2endpoint")..

在这里,您将实际对自己的终结点(在控制器中定义的终结点)进行 rest/api 调用。Spring将命中你的端点,执行你在控制器/服务层中的所有逻辑,当涉及到实际在外面进行调用的部分时,将使用你上面刚刚定义的mockServer。这样,它完全离线。您从未遇到过实际的外部服务。此外,您将在同一个 mockMvc.perform 方法上附加断言。


查看完整回答
反对 回复 2022-08-17
  • 2 回答
  • 0 关注
  • 96 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号