用于单元测试的模拟休息模板



我想在Spring Boot中模拟一个RestTemplate,在那里我在一个方法中进行REST调用。要测试我正在创建的微服务的控制器, 我想在微服务的控制器中测试方法。

例如:

@GetMapping(value = "/getMasterDataView", produces = { MediaType.APPLICATION_JSON_VALUE })
@CrossOrigin(origins = { "http://192.1**********" }, maxAge = 3000)
public ResponseEntity<MasterDataViewDTO> getMasterDataView() throws IOException {
final String uri = "http://localhost:8089/*********";
RestTemplate restTemplate = new RestTemplate();
MasterDataViewDTO masterDataViewDTO = restTemplate.getForObject(uri, MasterDataViewDTO.class);
return new ResponseEntity<>(masterDataViewDTO, HttpStatus.OK);
}

如何使用模拟来测试它?

这是我到目前为止所拥有的:

@Test
public void testgetMasterDataView() throws IOException {
MasterDataViewDTO masterDataViewDTO= mock(MasterDataViewDTO.class);
//String uri = "http://localhost:8089/*********"; 
Mockito.when(restTemplate.getForObject(Mockito.anyString(),ArgumentMatchers.any(Class.class))).thenReturn(masterDataViewDTO);
assertEquals("OK",inquiryController.getMasterDataView().getStatusCode());        
}

我在运行模拟时收到错误,方法getMasterDataView()被调用,其中的 REST 调用也被调用并抛出错误。如何编写测试,以便不调用 REST 终结点?如果可能的话,我想和Mockito一起做这件事。

在开始编写测试之前,您应该稍微更改一下代码。首先,如果你提取那个RestTemplate,并为它创建一个单独的bean,你会注入到你的控制器中,这会容易得多。

为此,请在@Configuration类或主类中添加类似以下内容:

@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}

此外,您必须从控制器中删除new RestTemplate(),并自动连接它,例如:

@Autowired
private RestTemplate restTemplate;

现在您已经完成了此操作,在测试中注入模拟RestTemplate将容易得多。

对于您的测试,您有两个选择:

要么
  1. 模拟RestTemplate,要么使用模拟框架(例如。莫基托)
  2. 或者,您可以使用MockRestServiceServer,它允许您编写测试来验证是否正确调用了 URL、请求是否匹配等。

使用莫米托进行测试

要使用 Mockito 模拟您的RestTemplate,您必须确保在测试中添加以下注释:

@RunWith(MockitoJUnitRunner.class)

之后,您可以执行以下操作:

@InjectMocks
private MyController controller;
@Mock
private RestTemplate restTemplate;

现在,您可以像这样调整测试:

@Test
public void testgetMasterDataView() throws IOException {
MasterDataViewDTO dto = new MasterDataViewDTO();
when(restTemplate.getForObject("http://localhost:8089/*********", MasterDataViewDTO.class)).thenReturn(dto);
ResponseEntity<MasterDataViewDTO> response = controller.getMasterDataView();
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).isEqualTo(dto);
}

你可以像在测试中那样嘲笑 DTO,但你不必这样做,而且我认为这样做没有任何好处。你必须嘲笑的是restTemplate.getForObject(..)电话。

使用MockRestServiceServer进行测试

另一种方法是使用MockRestServiceServer.为此,您必须在测试中使用以下注释:

@RunWith(SpringRunner.class)
@RestClientTest

然后你必须自动连接你的控制器和MockRestServiceServer,例如:

@Autowired
private MyController controller;
@Autowired
private MockRestServiceServer server;

现在你可以像这样编写测试:

@Test
public void testgetMasterDataView() throws IOException {
server
.expect(once(), requestTo("http://localhost:8089/*********"))
.andExpect(method(HttpMethod.GET))
.andRespond(withSuccess(new ClassPathResource("my-mocked-result.json"), MediaType.APPLICATION_JSON));
ResponseEntity<MasterDataViewDTO> response = controller.getMasterDataView();
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
// TODO: Write assertions to see if the DTO matches the JSON structure
}

除了测试实际的 REST 调用是否匹配之外,这还允许您测试您的 JSON 到 DTO 是否也有效。

您可以使用@RestClientTestMockRestServiceServer来实现此目的。他们的文档中提供了一个示例:

@RunWith(SpringRunner.class)
@RestClientTest(RemoteVehicleDetailsService.class)
public class ExampleRestClientTest {
@Autowired
private RemoteVehicleDetailsService service;
@Autowired
private MockRestServiceServer server;
@Test
public void getVehicleDetailsWhenResultIsSuccessShouldReturnDetails()
throws Exception {
this.server.expect(requestTo("/greet/details"))
.andRespond(withSuccess("hello", MediaType.TEXT_PLAIN));
String greeting = this.service.callRestService();
assertThat(greeting).isEqualTo("hello");
}
}
  1. 创建 bean,而不是在服务中使用new RestTemplate()

  2. 对 Bean 使用 Profile("!test"),仅用于非测试配置文件。

  3. 创建如下测试类:

    @SpringBootTest(properties = "spring.profiles.active:test")
    @ActiveProfiles("test")
    @RunWith(SpringRunner.class)
    @Log4j2
    @Transactional
    public class QabzinoMockTest {
    
    @Autowired
    private WebApplicationContext webApplicationContext;
    @Autowired
    private QabzinoLogRepository qabzinoLogRepository;
    private MockMvc mockMvc;
    private final WebServiceStatus successStatus = new WebServiceStatus();
    @Mock
    private RestTemplate restTemplate;
    private final Gson mapper = new Gson();
    @TestConfiguration
    static class Config {
    @Bean
    public RestTemplate rest() {
    return Mockito.mock(RestTemplate.class);
    }
    }
    @Before
    public void setup() throws Exception {
    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();
    this.restTemplate = (RestTemplate) this.webApplicationContext.getBean("rest");
    LoginOutput responseModel = new LoginOutput();
    responseModel.setStatus("200");
    Mockito.when(
    restTemplate.postForEntity(                            
    Mockito.eq(LOGIN_URL),
    Mockito.isA(HttpEntity.class),
    Mockito.eq(String.class)
    )
    ).thenReturn(ResponseEntity.ok().body(mapper.toJson(responseModel)));
    }
    }
    

在此示例中,我们在static class Config中创建具有rest名称的 Bean,并在所有测试之前在设置方法中模拟它。

  1. 首选测试配置可能对您有用application-test.properties

    spring.h2.console.enabled=true

    spring.jpa.defer-datasource-initialization=true

    spring.jpa.show-sql=true

    spring.jpa.generate-ddl=true

    spring.jpa.hibernate.ddl-auto=create

    spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect

    spring.datasource.driver-class-name=org.h2.Driver spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=真;忽略大小写=真;

    spring.datasource.username=sa

    spring.datasource.password=sa

最后,当我们在代码中看到 restTemplate 时,mock bean 返回我们的响应模型而不是真正的服务调用:)

相关内容

  • 没有找到相关文章

最新更新