如何使用 mockito 不评估测试方法中的方法

How to use mockito to not evaluate a method inside the testing method


我正在为控制器方法实现一个测试用例。控制器方法如下所示,

public class LoginController{
   public String register(String token){
     //some logic 
     loginService.delete(String token);
    //some logic
   return "xxxx";
   }
}

我正在实施测试用例以测试注册方法,我不希望评估删除方法。 (delete方法是一个服务方法,returns一个void)。我做了一些研究,并在我的测试方法中使用了下面的代码来不评估 delete 方法,但是当我调试它时它仍然进入 delete 方法。谁能指出我做错了什么。

public class LoginControllerTest{
   private loginService loginServiceMock;

   @Test
   public void testRegister(){
      loginServiceMock = new loginServiceImpl();
      loginService spy = spy(loginServiceMock);
      doNothing().when(spy).delete(any(String.class));
      //calling the controller method 
   }
}

spy 的整体思路是,它允许您在实际实例上调用和验证方法。因此,如果您调用一个间谍实例方法,它实际上会在实际实例上调用该方法,除非它被模拟。

对于你的情况,你需要使用 mock 而不是 spy:

@RunWith(MockitoJUnitRunner.class)
public class LoginControllerTest{

   @InjectMocks
   private LoginController controller;

   @Mock
   private loginService loginServiceMock; 


   @Test
   public void testRegister(){      

      doNothing().when(loginServiceMock).delete(anyString()));
      //calling the controller method 
      String value = controller.register("mytoken");
      verify(loginServiceMock,times(1)).delete(anyString());
   }
}

LoginController 重构为

public class LoginController {
    private LoginService loginService;

    public LoginController(LoginService loginService) {
        this.loginService = loginService;
    }

    public String register(String token){
        //some logic 
        loginService.delete(token);
        //some logic
        return "xxxx";
    }
 }

 public interface LoginService {
     void delete(String token);
 }

然后在你的测试中

public class LoginControllerTest {
   private LoginController loginController;

   @Test
   public void testRegister(){
      loginController = new LoginController(t -> {});

      loginController.register("foo");

      //do some assertion
   }
}

我知道这不是您(也许)期望的那种解决方案,但它解决了您的问题(不再调用真正的 delete)。

此解决方案的其他优势:

  • 代码更解耦,更易于维护
  • 上述的直接后果:代码变得更容易测试
  • 上述的直接后果:您不再需要做需要模拟的复杂事情

只要将 loginService spy 对象注入到您正在测试的 LoginController 中,您正在做的事情就应该有效。从您发布的代码中看不到这一点。

控制器调用真正的登录服务方法有两个原因:

  1. 您忘记将间谍程序注入控制器:类似于 loginControllerToTest = new LoginController(spy)loginControllerToTest.setLoginService(spy)

  2. loginService.delete() 是一种静态方法,在这种情况下,您需要重构代码以消除静态依赖或使用不同的模拟工具,例如 powermock。有关详细信息,请参阅