【问题标题】:Exception is not thrown when using Mockito's doThrow method使用 Mockito 的 doThrow 方法时不会抛出异常
【发布时间】:2019-02-12 12:52:41
【问题描述】:

我正在使用如下模拟对象:

@Mock
private RecipeService recipeService

我在测试类里面也有如下方法:

    @Test
    public void testAddRecipeWithNonUniqueName() throws Exception {
        Recipe recipe = new Recipe();

        doThrow(Exception.class)
                .when(recipeService)
                .save(recipe);

        mockMvc.perform(post("/recipes/add-recipe")
                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                .param("id", "1")
                .param("name", "recipe1"))
                .andExpect(status().is3xxRedirection())
                .andExpect(view().name("redirect:/recipes/add"));
    }

如您所见,我正在使用 mockito 的 doThrow 方法来决定在调用名为 savevoid 方法时将引发什么异常。

我想使用 MockMvc 对象发出 POST 请求。因此,标有/recipes/add-recipe 端点的方法将在我的一个控制器类中调用。以下 sn-p 代码详细显示了该方法:

    @RequestMapping(value = "/recipes/add-recipe", method = RequestMethod.POST)
    public String addRecipe(@Valid Recipe recipe, BindingResult result, RedirectAttributes redirectAttributes,
                            @AuthenticationPrincipal User user){

       String response = validateFormValues(recipe, redirectAttributes, result,
               "redirect:/recipes/add");
       if(!response.isEmpty())return response;

        recipe.setUser(user);

        try {
            recipeService.save(recipe);
        }catch(Exception e){
            redirectAttributes.addFlashAttribute("uniqueConstraintError",
                    String.format("The name \"%s\" is already taken by another recipe. " +
                                    "Please try again!",
                            recipe.getName()));
            return "redirect:/recipes/add";
        }

        setUserForIngredientsAndSteps(recipe);

        redirectAttributes.addFlashAttribute("flash",
                new FlashMessage("The recipe has been added successfully!", FlashMessage.Status.SUCCESS));
        return String.format("redirect:/recipes/%s/detail", recipe.getId());
    }

上述方法包含一个 try-catch 块。当recipeService.save() 被调用时,我期望会抛出一个异常,并由catch 块处理。 但这不会发生。 而是执行其他行。

我错过了什么?

【问题讨论】:

  • 你实际上是在哪里通过模拟?
  • 只有在调用完全相同的Recipe 实例时才会引发异常。而是使用any() 作为匹配器。
  • @M.Deinum 现在我明白了。我的一个简单的错误。但现在我会有一个不同的问题。在这种情况下,save 方法可以采用 RecipeList<Recipe> 对象。所以如果我打电话给any(),我会得到“不明确的方法调用”编译错误。这种情况我该怎么办?
  • 使用any(Recipe.class)
  • 附带说明,您几乎不应该catch Exception,当然也不在这里;除了重复项之外,还有许多其他错误条件,您不应一视同仁。

标签: java spring testing junit mockito


【解决方案1】:
Recipe recipe = new Recipe();

doThrow(Exception.class)
        .when(recipeService)
        .save(recipe);

仅当将完全相同的 Recipe 实例传递给 save 方法时,此代码才有效。如果您已经实现了 equals 和/或 hashCode 方法,则传入 Recipe 实例,如果预期值 1name 可能使其工作。

Recipe recipe = new Recipe();
recipe.setId(1);
recipe.setName("name");

doThrow(Exception.class)
        .when(recipeService)
        .save(recipe);

但是,由于您可能想要测试错误情况,因此总是抛出异常可能更容易。为此,请使用 any() 匹配器。

doThrow(Exception.class)
        .when(recipeService)
        .save(any(Recipe.class);

现在调用 save 时,不管传入的 Recipe 是什么,都会抛出异常。

【讨论】:

    【解决方案2】:

    您调用的doTrhow() 方法只有在您保存之前创建的特定配方时才会触发。

    你需要告诉 Mockito 使用任何食谱

    Mockito.doThrow(Exception.class)
                .when(recipeService)
                .save(Mockito.any(Recipe.class));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多