Spring 引导单元测试 MockMvc 空主体
Spring Boot Unit Testing MockMvc Null Body
我在使用 MockMvc 时遇到了困难。
这里我有简单的服务和控制器 类:
服务:
@Slf4j
@Service
public class EmployeeService {
//...
public Employee GetSample() {
//...
//filling Employee Entities
return new Employee(
"Harriet"
, "random"
, 25);
}
}
控制器:
@RestController
@RequestMapping(value = "/info")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Validated
public class EmployeeController {
private final EmployeeService employeeService;
@PostMapping("/GetEmployee")
public ResponseEntity<Employee> GetEmployee() {
Employee employee = employeeService.GetSample();
return new ResponseEntity<>(employee, HttpStatus.OK);
}
}
测试:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class EmployeeTestCase {
private MockMvc mockMvc;
@InjectMocks
private EmployeeController EmployeeController;
@Mock
private EmployeeService employeeService;
@Before
public void setUp() {
this.mockMvc = MockMvcBuilders.standaloneSetup(employeeController).build();
}
@Test
public void getEmployee() throws Exception {
this.mockMvc.perform(MockMvcRequestBuilders.post("/info/GetEmployee")).andDo(print());
}
}
当我尝试使用 MockMvc 时,我得到了空主体。似乎员工为空。但是我不明白为什么。
我认为当测试使用 perform
时,它应该初始化 employee 并且稍后它不应该为空。
我试图尽可能地削减代码。希望不要太长
注意:也尝试使用 Mockito.when(employeeController.GetEmployee()).thenCallRealMethod();
The @SpringBootTest annotation loads the complete Spring application
context. That means you do not mock your layers
(Services/Controllers).
如果您想测试应用程序的特定层,可以查看 Springboot
提供的测试切片注释:https://docs.spring.io/spring-boot/docs/current/reference/html/test-auto-configuration.html
相比之下,test slice
注释仅加载测试特定层所需的 bean。正因为如此,我们可以避免不必要的模拟和副作用。
测试切片的一个例子是@WebMvcTest
@ExtendWith(SpringExtension.class)
@WebMvcTest(controllers = HelloController.class,
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityConfig.class)
}
)
public class HelloControllerTest {
@Autowired
private MockMvc mvc;
@Test
public void hello() throws Exception {
String hello = "hello";
mvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string(hello));
}
@Test
public void helloDto() throws Exception {
String name = "hello";
int amount = 1000;
mvc.perform(
get("/hello/dto")
.param("name", name)
.param("amount", String.valueOf(amount)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name", is(name)))
.andExpect(jsonPath("$.amount", is(amount)));
}
}
但是,如果您真的想加载 SpringBoot 应用程序上下文,例如集成测试,那么您有几个选择:
@SpringBootTest
@AutoConfigureMockMvc
public class TestingWebApplicationTest {
@Autowired
private MockMvc mockMvc;
@Test
public void shouldReturnDefaultMessage() throws Exception {
this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello, World")));
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class AuctionControllerIntTest {
@Autowired
AuctionController controller;
@Autowired
ObjectMapper mapper;
MockMvc mockMvc;
@Before
public void setUp() throws Exception {
System.out.println("setup()...");
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
@Test
public void create_ValidAuction_ShouldAddNewAuction() throws Exception {
final Auction auction = new Auction(
"Standing Desk",
"Stand up desk to help you stretch your legs during the day.",
"Johnnie34",
350.00);
mockMvc.perform(post("/auctions")
.contentType(MediaType.APPLICATION_JSON)
.content(toJson(auction)))
.andExpect(status().isCreated());
}
}
假设您根本不想加载任何层,并且想模拟所有内容,例如单元测试:
@RunWith(MockitoJUnitRunner.class)
class DemoApplicationTest {
@Mock
private UserRepository userRepository;
private Demo noneAutoWiredDemoInstance;
@Test
public void testConstructorCreation() {
MockitoAnnotations.initMocks(this);
Mockito.when(userRepository.count()).thenReturn(0L);
noneAutoWiredDemoInstance = new Demo(userRepository);
Assertions.assertEquals("Count: 0", noneAutoWiredDemoInstance.toString());
}
}
我在使用 MockMvc 时遇到了困难。 这里我有简单的服务和控制器 类:
服务:
@Slf4j
@Service
public class EmployeeService {
//...
public Employee GetSample() {
//...
//filling Employee Entities
return new Employee(
"Harriet"
, "random"
, 25);
}
}
控制器:
@RestController
@RequestMapping(value = "/info")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Validated
public class EmployeeController {
private final EmployeeService employeeService;
@PostMapping("/GetEmployee")
public ResponseEntity<Employee> GetEmployee() {
Employee employee = employeeService.GetSample();
return new ResponseEntity<>(employee, HttpStatus.OK);
}
}
测试:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class EmployeeTestCase {
private MockMvc mockMvc;
@InjectMocks
private EmployeeController EmployeeController;
@Mock
private EmployeeService employeeService;
@Before
public void setUp() {
this.mockMvc = MockMvcBuilders.standaloneSetup(employeeController).build();
}
@Test
public void getEmployee() throws Exception {
this.mockMvc.perform(MockMvcRequestBuilders.post("/info/GetEmployee")).andDo(print());
}
}
当我尝试使用 MockMvc 时,我得到了空主体。似乎员工为空。但是我不明白为什么。
我认为当测试使用 perform
时,它应该初始化 employee 并且稍后它不应该为空。
我试图尽可能地削减代码。希望不要太长
注意:也尝试使用 Mockito.when(employeeController.GetEmployee()).thenCallRealMethod();
The @SpringBootTest annotation loads the complete Spring application context. That means you do not mock your layers (Services/Controllers).
如果您想测试应用程序的特定层,可以查看 Springboot
提供的测试切片注释:https://docs.spring.io/spring-boot/docs/current/reference/html/test-auto-configuration.html
相比之下,test slice
注释仅加载测试特定层所需的 bean。正因为如此,我们可以避免不必要的模拟和副作用。
测试切片的一个例子是@WebMvcTest
@ExtendWith(SpringExtension.class)
@WebMvcTest(controllers = HelloController.class,
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityConfig.class)
}
)
public class HelloControllerTest {
@Autowired
private MockMvc mvc;
@Test
public void hello() throws Exception {
String hello = "hello";
mvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string(hello));
}
@Test
public void helloDto() throws Exception {
String name = "hello";
int amount = 1000;
mvc.perform(
get("/hello/dto")
.param("name", name)
.param("amount", String.valueOf(amount)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name", is(name)))
.andExpect(jsonPath("$.amount", is(amount)));
}
}
但是,如果您真的想加载 SpringBoot 应用程序上下文,例如集成测试,那么您有几个选择:
@SpringBootTest
@AutoConfigureMockMvc
public class TestingWebApplicationTest {
@Autowired
private MockMvc mockMvc;
@Test
public void shouldReturnDefaultMessage() throws Exception {
this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello, World")));
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class AuctionControllerIntTest {
@Autowired
AuctionController controller;
@Autowired
ObjectMapper mapper;
MockMvc mockMvc;
@Before
public void setUp() throws Exception {
System.out.println("setup()...");
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
@Test
public void create_ValidAuction_ShouldAddNewAuction() throws Exception {
final Auction auction = new Auction(
"Standing Desk",
"Stand up desk to help you stretch your legs during the day.",
"Johnnie34",
350.00);
mockMvc.perform(post("/auctions")
.contentType(MediaType.APPLICATION_JSON)
.content(toJson(auction)))
.andExpect(status().isCreated());
}
}
假设您根本不想加载任何层,并且想模拟所有内容,例如单元测试:
@RunWith(MockitoJUnitRunner.class)
class DemoApplicationTest {
@Mock
private UserRepository userRepository;
private Demo noneAutoWiredDemoInstance;
@Test
public void testConstructorCreation() {
MockitoAnnotations.initMocks(this);
Mockito.when(userRepository.count()).thenReturn(0L);
noneAutoWiredDemoInstance = new Demo(userRepository);
Assertions.assertEquals("Count: 0", noneAutoWiredDemoInstance.toString());
}
}