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());
    }
}