单元测试利器——手把手教你使用Mockito(三)

发表于:2023-3-27 09:30

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:秦浩然    来源:知乎

  三、学习了这么多,牛刀小试一下!
  测试实体类:
  @Data
  public class User {
      /**
       * 姓名,登录密码
       */
  持久层 DAO:
  public interface UserDao {
      /**
       * 根据name查找user
       * @param name
       * @return
       */
      User getUserByName(String name);
      /**
       * 保存user
       * @param user
       * @return
       */
      Integer saveUser(User user);
  }
  业务层 Service 接口:
  public interface UserService {
      /**
       * 根据name查找user
       * @param name
       * @return
       */
      User getUserByName(String name);
      /**
       * 保存user
       * @param user
       * @return
       */
      Integer saveUser(User user);
  }
  业务层 Serive 实现类:
  @Service
  public class UserServiceImpl implements UserService {
      //userDao
      @Autowired
      private UserDao userDao;
      /**
       * 根据name查找user
       * @param name
       * @return
       */
      @Override
      public User getUserByName(String name) {
          try {
              return userDao.getUserByName(name);
          } catch (Exception e) {
              throw new RuntimeException("查询user异常");
          }
      }
      /**
       * 保存user
       * @param user
       * @return
       */
      @Override
      public Integer saveUser(User user) {
          if (userDao.getUserByName(user.getName()) != null) {
              throw new RuntimeException("用户名已存在");
          }
          try {
              return userDao.saveUser(user);
          } catch (Exception e) {
              throw new RuntimeException("保存用户异常");
          }
      }
  }
  现在我们的 Service 写好了,想要单元测试一下,但是 Dao 是其他人开发的,目前还没有写好,那我们如何测试呢?
  public class UserServiceTest {
      /**
       * Mock测试:根据name查询user
       */
      @Test
      public void getUserByNameTest() {
          // mock对象
          final UserDao userDao = mock(UserDao.class);
          final UserServiceImpl userService = new UserServiceImpl();
          userService.setUserDao(userDao);
          // stub调用
          final User user = new User();
          user.setName("admin");
          user.setPassword("pass");
          when(userDao.getUserByName("admin")).thenReturn(user);
          // 执行待测试方法
          final User user1 = userService.getUserByName("admin");
          System.out.println("查询结果:" + JacksonUtil.obj2json(user1));  //查询结果:{"name":"admin","password":"pass"}
          // 验证mock对象交互
          verify(userDao).getUserByName(anyString());
          // 验证查询结果
          Assert.assertNotNull("查询结果为空!", user1);
          Assert.assertEquals("查询结果错误!", "admin", user1.getName());
      }
      /**
       * Mock测试:保存user
       */
      @Mock
      private UserDao userDao;
      @InjectMocks
      private UserServiceImpl userService;
      @Test
      public void saveUserTest() throws Exception{
          // 执行注解初始化
          MockitoAnnotations.initMocks(this);
          // mock对象stub操作
          final User user = new User();
          user.setName("admin");
          user.setPassword("pass");
          when(userDao.getUserByName("admin")).thenReturn(user).thenReturn(null);
          when(userDao.saveUser(any(User.class))).thenReturn(1);
          // 验证用户名重复的情况
          try {
              userService.saveUser(user);
              throw new Exception();  //走到这里说明验证失败
          } catch (RuntimeException e) {
              System.out.println("重复用户名保存失败-测试通过");   //重复用户名保存失败-测试通过
          }
          verify(userDao).getUserByName("admin");
          // 验证正常保存的情况
          user.setName("user");
          final Integer integer = userService.saveUser(user);
          System.out.println("保存结果:" + integer);  //保存结果:1
          Assert.assertEquals("保存失败!", 1, integer.longValue());
          verify(userDao).saveUser(any(User.class));
          verify(userDao, times(2)).getUserByName(anyString());
      }
  }
  根据以上代码我们可以知道,当我们的待测类开发完成而依赖的类的实现还没有开发完成。此时,我们就可以用到我们的 Mock 测试,模拟我们依赖类的返回值,使我们的待测类与依赖类解耦。这样,我们就可以对我们的待测类进行单元测了。
  四、参考文档及进一步学习~
  Mockito英文版javadoc:https://javadoc.io/static/org.mockito/mockito-core/3.3.3/org/mockito/Mockito.html
  Mockito中文文档(部分):https://blog.csdn.net/bboyfeiyu/article/details/52127551#35
  Mockito使用教程:https://www.cnblogs.com/Ming8006/p/6297333.html
  参数捕获器使用:https://www.journaldev.com/21892/mockito-argumentcaptor-captor-annotation
  利用ArgumentCaptor(参数捕获器)捕获方法参数进行验证:https://www.iteye.com/blog/hotdog-916364
  改变mock返回值:https://www.huangyunkun.com/2014/10/25/mockito-deep-stub-with-enum/
  五分钟了解Mockito:https://www.iteye.com/blog/liuzhijun-1512780
  使用Mockito进行单元测试:https://www.iteye.com/blog/qiuguo0205-1443344
  JUnit + Mockito 单元测试:https://blog.csdn.net/zhangxin09/article/details/42422643
  Mockito中@Mock与@InjectMock:https://www.cnblogs.com/langren1992/p/9681600.html
  mockito中两种部分mock的实现,spy、callRealMethod:https://www.cnblogs.com/softidea/p/4204389.html
  Mockito 中被 Mocked 的对象属性及方法的默认值:https://www.cnblogs.com/fnlingnzb-learner/p/10635250.html
  单元测试工具之Mockito:https://blog.csdn.net/qq_32140971/article/details/90598454
  引入Mockito测试用@Spy和@Mock:https://blog.csdn.net/message_lx/article/details/83308114
  Mockito初探(含实例):https://www.iteye.com/blog/sgq0085-2031319
  测试覆盖率统计:https://blog.csdn.net/lvyuan1234/article/details/82836052?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
  测试覆盖率无法统计解决:https://blog.csdn.net/zhanglei082319/article/details/81536398
  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号