当我指定我的类型的 Optional 时,为什么 Mockito return null

Why does Mockito return null when I specify an Optional of my type

我在控制器上有一个方法可以获取聊天室所有惩罚类型的列表(踢、禁止、警告和静音)。在第一次测试中,当我模拟数据时,它按预期工作并且测试通过。

然而,在我的第二次测试中,我提供了。我将应该 returned 的内容定义为 Optional<Punishment>,并将 punishmentName 的属性设置为“静音”。我很困惑为什么这会给我 null。当我在测试之外 运行 Spring 应用程序时,路由工作正常。出于某种原因,模拟从不想 return 我指定的值,但只是空值。具体来说,这是在 .andExpect(jsonPath("$.punishmentName", Matchers.equalTo("mute"))); 行的测试中发现的,因为字段值为 null 并给出以下错误:

java.lang.AssertionError: No value at JSON path "$.punishmentName"

为清楚起见,我还提供了控制器方法和服务方法。

惩罚控制器测试:

@WebMvcTest(PunishmentController.class)
@RunWith(SpringRunner.class)
public class PunishmentControllerTest {

@Autowired
private MockMvc mvc;

@MockBean
private PunishmentService punishmentService;

@MockBean
private PunishmentValidator punishmentValidator;

@Test
public void getAllPunishmentTypesReturnsAListOfPunishmentTypes() throws Exception {
    List<Punishment> punishments = new ArrayList<>();
    punishments.add(new Punishment("mute"));
    punishments.add(new Punishment("kick"));
    punishments.add(new Punishment("ban"));
    punishments.add(new Punishment("warn"));

    Mockito.when(punishmentService.getAllPunishmentTypes()).thenReturn(punishments);

    mvc.perform(get("/api/punishments"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$", Matchers.hasSize(4)))
            .andExpect(jsonPath("$[0].punishmentName", Matchers.equalTo("mute")))
            .andExpect(jsonPath("$[1].punishmentName", Matchers.equalTo("kick")))
            .andExpect(jsonPath("$[2].punishmentName", Matchers.equalTo("ban")))
            .andExpect(jsonPath("$[3].punishmentName", Matchers.equalTo("warn")));
}

@Test
public void getPunishmentTypeReturnsMuteWhenMuteIsSpecified() throws Exception {
    Optional<Punishment> mute = Optional.of(new Punishment("mute"));
    Mockito.when(punishmentService.getPunishmentType("mute")).thenReturn(mute);

    mvc.perform(get("/api/punishments/mute"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.punishmentName", Matchers.equalTo("mute")));
}

控制器方法:

    /**
     * GET request for all punishment types.
     * @return List<Punishment> - When Punishments are found in the database they are returned in a List object.
     *                            Otherwise, an empty list is returned if no records are found or an error occurs.
     */
    @GetMapping
    public List<Punishment> getAllPunishments() {
        return punishmentService.getAllPunishmentTypes();
    }

    /**
     * GET request for one punishment type.
     * @param punishmentType String - The type of punishment.
     * @return Optional<Punishment> - The rule that gets returned or an empty optional if no rule is found.
     */
    @GetMapping(path = "{punishmentType}")
    public Optional<Punishment> getPunishment(@PathVariable("punishmentType") String punishmentType) {
        boolean isPunishmentTypeValid = punishmentValidator.validatePunishmentName(punishmentType);

        if (isPunishmentTypeValid) {
            return punishmentService.getPunishmentType(punishmentType);
        } else {
            return Optional.empty();
        }
    }
}

服务方式:

    /**
     * Gets all the punishment types
     * @return List<Punishment> - The rules in the community
     */
    public List<Punishment> getAllPunishmentTypes() {
        return punishmentRepository.findAll();
    }

    /**
     * Gets a specific punishment type.
     * @param punishmentType String - The type of punishment.
     * @return The punishment retrieved.
     */
    public Optional<Punishment> getPunishmentType(String punishmentType) {
        return punishmentRepository.findById(punishmentType);
    }

我相信这是因为你忘记模拟方法 PunishmentValidator#validatePunishmentName("mute") 到 return true 这样你在 PunishmentService 上存根的方法永远不会被调用,因为默认情况下,如果您不存根方法,它将 return false(参见 this)。

另外它是一个 known behaviour that @MockBean is configured as lenient stubbing 如果你存根一个方法但它实际上没有被执行,它不会报告错误(即抛出 UnnecessaryStubbingException)。

所以更改以下内容应该可以解决您的问题:

@Test
public void getPunishmentTypeReturnsMuteWhenMuteIsSpecified() throws Exception {
    Optional<Punishment> mute = Optional.of(new Punishment("mute"));
    
    Mockito.when(punishmentService.getPunishmentType("mute")).thenReturn(mute);
    Mockito.when(punishmentValidator.validatePunishmentName("mute")).thenReturn(true);

    mvc.perform(get("/api/punishments/mute"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.punishmentName", Matchers.equalTo("mute")));
}