无法模拟 RestTemplate.exchange
Unable to Mock RestTemplate.exchange
作为 TDD 的一部分,我希望能够测试我的 SpringBoot rest 应用程序的每个部分。但是我无法模拟外部调用。
应用结构
1.很少有内部调用外部休息端点的休息端点。
2. 所有对外部端点的调用都通过本地 http 客户端编排,该客户端使用 RestTemplate 作为 httpClient。
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.MOCK, classes = TestDrivenDevelopmentWithJavaApplication.class)
public class TestDrivenDevelopmentWithJavaApplicationTests {
@Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
@MockBean
private RestTemplate client;
@Before
public void setup() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
Structure1Root category = new Structure1Root();
Category cat = new Category();
cat.setCategoryName("Test1");
cat.setDescription("Test");
category.setD(cat);
Mockito.when(client.exchange(
ArgumentMatchers.eq("https://services.odata.org/V2/Northwind/Northwind.svc/Products(1)?$format=json"),
ArgumentMatchers.eq(HttpMethod.GET), ArgumentMatchers.eq(null),
ArgumentMatchers.eq(Structure1Root.class)))
.thenReturn(new ResponseEntity<Structure1Root>(category, HttpStatus.OK));
}
@Test
public void testendpoint1() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/api/endpoint1?token=1").contentType(MediaType.APPLICATION_JSON))
.andExpect(content().string(org.hamcrest.Matchers.containsString("Test1")));
}
}
尽管我已经在 client.exchange(RestTemplate.exchange) 上设置了模拟,但我看到 client.exchange 返回的响应是空的,而不是 thenReturn
[ 中指定的响应=17=]
控制器代码
@RestController
@RequestMapping(path = Endpoint.base)
public class Endpoint {
public static final String base = "/api";
@Autowired
MyHttpClient<Structure2Root> client;
@Autowired
MyHttpClient<Structure1Root> Cclient;
@GetMapping(path = "/endpoint1")
public ResponseEntity<Structure2Root> callEndpt1(@RequestParam String token) {
Response<Structure2Root> resp = client
.execute("https://services.odata.org/V2/Northwind/Northwind.svc/Products(1)?$format=json", Structure2Root.class);
return new ResponseEntity<Structure2Root>(resp.getResponse(), HttpStatus.OK);
}
@GetMapping(path = "/endpoint2")
public ResponseEntity<Structure1Root> callEndpt2(@RequestParam String token) {
Response<Structure1Root> resp = Cclient.execute(
"https://services.odata.org/V2/Northwind/Northwind.svc/Categories(1)?$format=json", Structure1Root.class);
return new ResponseEntity<Structure1Root>(resp.getResponse(),HttpStatus.OK);
}
}
最后,本地 http 客户端代码
@Service
public class MyHttpClient<O> {
@Autowired
RestTemplate client;
public MyHttpClient() {
// TODO Auto-generated constructor stub
}
public Response<O> execute(String url, Class<O> generic) {
ResponseEntity<O> resp = client.exchange(url, HttpMethod.GET, null, generic);
return new Response<O>(resp.getStatusCode(), resp.getBody());
}
}
这个client.execute
是我打算在第一个代码块中拦截的
然而似乎从来没有用过并且总是 returns 一个空值。
Git Repo
此致,
薇拉
您在模拟时使用了错误的对象。您应该使用 Structure2Root 而不是 Structure1Root
下面是正确的测试 class,它运行良好。
package com.demo.samples.tdd;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import com.demo.samples.tdd.responses.Product;
import com.demo.samples.tdd.responses.Structure2Root;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.WebApplicationContext;
import com.demo.samples.tdd.responses.Category;
import com.demo.samples.tdd.responses.Structure1Root;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.MOCK, classes = TestDrivenDevelopmentWithJavaApplication.class)
public class TestDrivenDevelopmentWithJavaApplicationTests {
@Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
@MockBean
private RestTemplate client;
@Before
public void setup() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
// Structure1Root category = new Structure1Root();
// Category cat = new Category();
// cat.setCategoryName("Test1");
// cat.setDescription("Test");
// category.setD(cat);
//
// Mockito.when(client.exchange(
// ArgumentMatchers.eq("https://services.odata.org/V2/Northwind/Northwind.svc/Products(1)?$format=json"),
// ArgumentMatchers.eq(HttpMethod.GET), ArgumentMatchers.eq(null),
// ArgumentMatchers.eq(Structure1Root.class)))
// .thenReturn(new ResponseEntity<Structure1Root>(category, HttpStatus.OK));
Structure2Root category2 = new Structure2Root();
Product product = new Product();
product.setProductName("Test1");
product.setUnitPrice("1");
category2.setD(product);
Mockito.when(client.exchange(
ArgumentMatchers.eq("https://services.odata.org/V2/Northwind/Northwind.svc/Products(1)?$format=json"),
ArgumentMatchers.eq(HttpMethod.GET), ArgumentMatchers.eq(null),
ArgumentMatchers.eq(Structure2Root.class)))
.thenReturn(new ResponseEntity<Structure2Root>(category2, HttpStatus.OK));
}
@Test
public void testendpoint1() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/api/endpoint1?token=1").contentType(MediaType.APPLICATION_JSON))
.andExpect(content().string(org.hamcrest.Matchers.containsString("Test1")));
}
}
作为 TDD 的一部分,我希望能够测试我的 SpringBoot rest 应用程序的每个部分。但是我无法模拟外部调用。
应用结构
1.很少有内部调用外部休息端点的休息端点。
2. 所有对外部端点的调用都通过本地 http 客户端编排,该客户端使用 RestTemplate 作为 httpClient。
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.MOCK, classes = TestDrivenDevelopmentWithJavaApplication.class)
public class TestDrivenDevelopmentWithJavaApplicationTests {
@Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
@MockBean
private RestTemplate client;
@Before
public void setup() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
Structure1Root category = new Structure1Root();
Category cat = new Category();
cat.setCategoryName("Test1");
cat.setDescription("Test");
category.setD(cat);
Mockito.when(client.exchange(
ArgumentMatchers.eq("https://services.odata.org/V2/Northwind/Northwind.svc/Products(1)?$format=json"),
ArgumentMatchers.eq(HttpMethod.GET), ArgumentMatchers.eq(null),
ArgumentMatchers.eq(Structure1Root.class)))
.thenReturn(new ResponseEntity<Structure1Root>(category, HttpStatus.OK));
}
@Test
public void testendpoint1() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/api/endpoint1?token=1").contentType(MediaType.APPLICATION_JSON))
.andExpect(content().string(org.hamcrest.Matchers.containsString("Test1")));
}
}
尽管我已经在 client.exchange(RestTemplate.exchange) 上设置了模拟,但我看到 client.exchange 返回的响应是空的,而不是 thenReturn
[ 中指定的响应=17=]
控制器代码
@RestController
@RequestMapping(path = Endpoint.base)
public class Endpoint {
public static final String base = "/api";
@Autowired
MyHttpClient<Structure2Root> client;
@Autowired
MyHttpClient<Structure1Root> Cclient;
@GetMapping(path = "/endpoint1")
public ResponseEntity<Structure2Root> callEndpt1(@RequestParam String token) {
Response<Structure2Root> resp = client
.execute("https://services.odata.org/V2/Northwind/Northwind.svc/Products(1)?$format=json", Structure2Root.class);
return new ResponseEntity<Structure2Root>(resp.getResponse(), HttpStatus.OK);
}
@GetMapping(path = "/endpoint2")
public ResponseEntity<Structure1Root> callEndpt2(@RequestParam String token) {
Response<Structure1Root> resp = Cclient.execute(
"https://services.odata.org/V2/Northwind/Northwind.svc/Categories(1)?$format=json", Structure1Root.class);
return new ResponseEntity<Structure1Root>(resp.getResponse(),HttpStatus.OK);
}
}
最后,本地 http 客户端代码
@Service
public class MyHttpClient<O> {
@Autowired
RestTemplate client;
public MyHttpClient() {
// TODO Auto-generated constructor stub
}
public Response<O> execute(String url, Class<O> generic) {
ResponseEntity<O> resp = client.exchange(url, HttpMethod.GET, null, generic);
return new Response<O>(resp.getStatusCode(), resp.getBody());
}
}
这个client.execute
是我打算在第一个代码块中拦截的
然而似乎从来没有用过并且总是 returns 一个空值。 Git Repo
此致,
薇拉
您在模拟时使用了错误的对象。您应该使用 Structure2Root 而不是 Structure1Root
下面是正确的测试 class,它运行良好。
package com.demo.samples.tdd;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import com.demo.samples.tdd.responses.Product;
import com.demo.samples.tdd.responses.Structure2Root;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.WebApplicationContext;
import com.demo.samples.tdd.responses.Category;
import com.demo.samples.tdd.responses.Structure1Root;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.MOCK, classes = TestDrivenDevelopmentWithJavaApplication.class)
public class TestDrivenDevelopmentWithJavaApplicationTests {
@Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
@MockBean
private RestTemplate client;
@Before
public void setup() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
// Structure1Root category = new Structure1Root();
// Category cat = new Category();
// cat.setCategoryName("Test1");
// cat.setDescription("Test");
// category.setD(cat);
//
// Mockito.when(client.exchange(
// ArgumentMatchers.eq("https://services.odata.org/V2/Northwind/Northwind.svc/Products(1)?$format=json"),
// ArgumentMatchers.eq(HttpMethod.GET), ArgumentMatchers.eq(null),
// ArgumentMatchers.eq(Structure1Root.class)))
// .thenReturn(new ResponseEntity<Structure1Root>(category, HttpStatus.OK));
Structure2Root category2 = new Structure2Root();
Product product = new Product();
product.setProductName("Test1");
product.setUnitPrice("1");
category2.setD(product);
Mockito.when(client.exchange(
ArgumentMatchers.eq("https://services.odata.org/V2/Northwind/Northwind.svc/Products(1)?$format=json"),
ArgumentMatchers.eq(HttpMethod.GET), ArgumentMatchers.eq(null),
ArgumentMatchers.eq(Structure2Root.class)))
.thenReturn(new ResponseEntity<Structure2Root>(category2, HttpStatus.OK));
}
@Test
public void testendpoint1() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/api/endpoint1?token=1").contentType(MediaType.APPLICATION_JSON))
.andExpect(content().string(org.hamcrest.Matchers.containsString("Test1")));
}
}