当前位置: 首页 > 知识库问答 >
问题:

如何在JUnit测试Java中替换Mockito来存根类

刁冠宇
2023-03-14

我试图用JUnit在测试会话期间正确使用Mockito来代替存根类。不幸的是,在网络上有很多关于Mockito的教程,但关于存根方法的教程较少,我想学习这项技术。

此测试由Mockito进行:

 @Test
public void addWrongNewUserSpaceInUsername() throws Exception {

    when(userValidator.isValidUsername(user.getUsername())).thenReturn(false);

    try {
        mockMvc.perform(
                post("/register")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(asJsonString(user)
                        ));
    } catch (Exception e) {
        Assert.assertTrue(e.getCause() instanceof UsernameNotValidException);
    }
}

为了澄清这些是所涉及的类:

1) 控制器

   @RestController
public class UserController {

    @Autowired
    RepositoryUserDB repositoryUserDB;

    @Autowired
    UserValidator userValidator;

    @RequestMapping(value = "/register", method = RequestMethod.POST)
    public User createUser(@RequestBody User user) {


        if (userValidator.isValidUsername(user.getUsername())) {

            if(!userValidator.isValidPassword(user.getPassword())){
                throw new PasswordNotValidException();
            }

            if(userValidator.isValidDateOfBirth(user.getDateOfBirth()) == false){
                throw new DOBNotValidException();
            }

            // se lo user e' gia' presente
            if (repositoryUserDB.getUserByUsername(user.getUsername()) == null) {
                return repositoryUserDB.createUser(user);
            }
            throw new UsernameAlreadyExistException();
        } else throw new UsernameNotValidException();

    }
}

2)回购接口:

public interface RepositoryUserDB {

    User getUserByUsername(String username);

    User createUser(User user);
}

3) 回购协议:

@Component

    public class MemoryUserDB implements RepositoryUserDB{

        Map<String, User> repo;

        public MemoryUserDB() {
            this.repo = new HashMap<>();
        }

        @Override
        public  User getUserByUsername(String username) {
            return repo.get(username);
        }

        @Override
        public User createUser(User user) {
            repo.put(user.getUsername(),user);
            return repo.get(user.getUsername());
        }
    }

4) 验证器:

   @Component
public class UserValidator {

    public boolean isValidUsername(String username) {
        return username.matches("^[a-zA-Z0-9]+$");
    }

    public boolean isValidPassword(String pwd) {
        if (pwd == null)
            return false;
        return pwd.matches("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d){4,}.+$");
    }

    public boolean isValidDateOfBirth(String DOB) {
        return DOB.matches("^(?:(?:(?:0?[13578]|1[02])(\\/|-|\\.)31)\\1|(?:(?:0?[1,3-9]|1[0-2])(\\/|-|\\.)(?:29|30)\\2))(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$|^(?:0?2(\\/|-|\\.)29\\3(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0?[1-9])|(?:1[0-2]))(\\/|-|\\.)(?:0?[1-9]|1\\d|2[0-8])\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$");
    }
}

5) RecentyExceptionHandler

    @ControllerAdvice
public class RestEntityExceptionHandler {

    @ExceptionHandler(UsernameNotValidException.class)
    @ResponseStatus(value = HttpStatus.FORBIDDEN, reason = "username wrong")
    public void handleUsernameException() {
    }

    @ExceptionHandler(UsernameAlreadyExistException.class)
    @ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "the username is already presents")
    public void handleUsername() {
    }

    @ExceptionHandler(PasswordNotValidException.class)
    @ResponseStatus(value = HttpStatus.FORBIDDEN, reason = "password wrong")
    public void handlePasswordException() {
    }

    @ExceptionHandler(DOBNotValidException.class)
    @ResponseStatus(value = HttpStatus.FORBIDDEN, reason = "Date Of Birth wrong")
    public void handleDOBException(){
    }

}

共有1个答案

沈凯康
2023-03-14

从理论上讲,对于你的用例来说,存根方法应该相当简单。
但是当你依赖于使用Spring bean容器的Spring Boot Test时,事情真的很难设置,因为你应该找到一种方法来注入模拟的bean替换实际bean的容器:UserValidator。Spring Boot测试中的Mocks通常依赖Spring BootMockBean
这不是mockito mock,但也不是很远。
要理解Mockito mock的差异,你可以参考这个问题。

使用框架提供了许多现成的功能,但也限制了你自己,因为你想绕过框架功能

假设您没有使用Spring Boot执行集成测试,而是执行真正的单元测试(因此没有Spring Boot容器),那么事情就可以这样执行

而不是模仿UserValidator。isValidUsername(),您定义了一个自定义的UserValidator实现,它按照测试中的预期存根方法返回
最后,Mockito或任何mock框架为您做了什么

下面是存根类:

public class UserValidatorStub extends UserValidator {

    private String expectedUsername;
    private boolean isValidUsername;

    public UserValidatorStub(String expectedUsername, boolean isValidUsername){
          this.expectedUsername = expectedUsername;
          this.isValidUsername = isValidUsername;
    }
    public boolean isValidUsername(String username) {
        if (username.equals(expectedUsername)){
           return isValidUsername;
        }
        // as fallback, it uses the default implementation but you may return false or null as alternative
       return super.isValidUsername(username);
    }

}

它接受一个构造函数来存储传递给存根方法的预期参数和要返回的存根结果。

现在,这里是如何编写测试的:

 @Test
public void addWrongNewUserSpaceInUsername() throws Exception {

    // inject the mock in the class under test
    UserController userController = new UserController(new UserValidatorStub(user.getUsername(), false));
    try {
        userController.createUser(user);
    } catch (Exception e) {
        Assert.assertTrue(e.getCause() instanceof UsernameNotValidException);
    }
}

请注意,该示例依赖于UserController中的构造函数注入来设置依赖项

 类似资料:
  • 我正在使用Mockito编写一个JUnit测试用例,并得到一个NullPointerException。 在我的代码中是这样的:

  • 问题内容: 我曾经使用过JUnit和Mocks,但我想知道,JUnit中的Mocks和Stub之间有什么区别,以及如何在JUnit,Java中使用Stub?作为具有EasyMock,Mockito等的Mocks,Stubs在Java中使用什么? 请提供Java中的存根示例代码。 问题答案: 要在junit中使用存根,您不需要任何框架。 如果您想存根某些接口,只需实现它: 然后创建一个新的存根对象并

  • 我能够测试代码,但代码覆盖率不包括第二个开关情况。 请参考以下代码。 下面是我的测试代码。 由于我已经声明了一个带有测试值的字符串变量,所以我无法涵盖第二个switch语句。我尝试过if else的情况,但同样的问题发生了。我们还有别的办法吗?

  • 我应该如何测试异常?我可以mock connector并且我可以赋予它抛出异常的行为,但是我不明白下一步该怎么做。

  • 我在我的Java,Spring Boot控制器中创建了一个函数,它允许我根据参数获得数据的和值,这很有效。然而,我很难理解用Junit和Mockito测试这个功能的最佳方式是什么?到目前为止,我已经创建了一个测试函数,它返回一个特定数组字段的值。如何能够返回。thenreturn()中的值,该值根据给定的serviceID求和?任何帮助或建议任何其他有用的帖子将被感谢,因为我无法找到任何相关的或我