面向接口编程的测试难的问题

Mock Framework的用处在于我们可以在不实现具体对象的情况下,即在没有某个类的实例的情况下对该对象的行为进行模拟。这一特征对于面向接口的编程非常有用。因为接口的调用者可以在没有接口的具体实现的情况下使用接口,也就是说调用者可以先于接口的实现者行动。也许有人觉得这好像没什么神奇的,即使没有mock我也一样可以使用接口啊,可是我要问:

“在没有接口实现的情况下,你能对调用接口的代码进行测试吗?”

“NullReferenceException”相信很多人都碰到过的吧。由于接口不能定义构造函数,也就无法实例化,导致了调用接口的代码无法运行,当然也就是无法测试。

Mocking能干什么?

从mock 的字面意思就可以了解一二了,它的主要工作是模拟出一个被模拟对象的实例,其中包括模拟对该实例的调用行为(比如访问属性、调用方法之类)、模拟方法或属性访问的返回值、模拟方法和索引的参数传递等等,可以说基本上对于一个对象实例的使用它都可以模拟出来。这样一来,我们就可以好像真的有一个我们需要的实例存在一样,正常地使用它,来完成对调用者代码的开发和测试。

Mock object和stub object一样吗?

当然不一样!写过stub测试程序的人应该知道,stub是真是对象的一个模拟,比如调用者需要一个值,那就让stub输出一个值,如果调用者需要传递一个值给stub,那就在stub中定义一个方法接受该参数。但是这与mock的对象存在本质的区别:

stub虽然说也是模拟,但其本质上对真是对象的一个简单实现,而无论它有多简单它都是一种实现,它是真是存在的,它里面包含了我们定义的操作代码;

反观mock的对象,它根本是不存在的,哪怕一句的简单的不能再简单的代码都不存在。

在理解其区别之前,需要明白一点,他们都是为了同一个目标而出现的,代替依赖部分,让原先的“整合测试”简化为“单元测试”。

mock:使用easymock等包,在程序代码中向被测试代码注入“依赖部分”,通过代码可编程的方式模拟出函数调用返回的结果。

stub:自己写代码代替“依赖部分”。它本身就是“依赖部分”的一个简化实现。

实际上,在能够使用mock的时候,就不应该选择使用stub。但是有时候是必须使用stub的,例如在对遗留代码进行测试时,该部分代码不支持“注入”,那么只能将“替代”这个过程外移,使用stub完成此任务了。

应用场景

就以我现在正在开发这个网站代码为例,来说一下如果在测试的使用Mock object.现在有一个需求,我们需要根据给定的搜索关键字和搜索范围来进行项目的搜索,以MVP的方式实现的话我们定义了一个IView接口:

public interface IView_SearchProject
  {
    void AttachPresenter(Presenter_SearchProject presenterSearchProject);
    SearchRange Range { get;}
    string SearchKey { get;}
    string UrlBase { get;}
    void NavigateTo(string searchUrl);
  }

以及一个Presenter:

public class Presenter_SearchProject
  {
    public Presenter_SearchProject(IView_SearchProject viewSearch)
    {
        view = viewSearch;
        range = view.Range;
        prjNav = new ProjectSearchNavigator(view.UrlBase);
        query = new SearchQuery();
    }

public string GetDesUrl()
    {
        query.WithDescription = range.WithDescription;
        query.WithName = range.WithName;
        query.WithKey = range.WithKey;
        query.SearchKey = view.SearchKey;
        query.Ids = range.Ids;

prjNav.Compile(query);
        return prjNav.DestUrl;
    }

public void Search()
    {
        view.NavigateTo(GetDesUrl());
    }

private IView_SearchProject view;
    private SearchRange range;
    private ProjectSearchNavigator prjNav;
    private SearchQuery query;
  }

ProjectSearchNavigator是一个实现页面跳转的帮助类,负责根据View(这里是一个aspx的页面)传递的搜索关键字SearchKey和querystring构造出搜索页面的地址。SearchQuery类负责解析Request.QueryString集合,因为其中存储的key/value对,需要据此构造出所有查询条件的一个字符串。
Mocking and Testing

Mocking说到底多试为了测试,否则我们没有必要,因为mocking出来的对象并不能作为的真是的代码运行。先把测试的代码贴出来,再进行解释,希望你不要觉得太多了:)

[TestFixture]
  public class Presenter_SearchProject_Test
  {
    [SetUp]
    public void SetUp()
    {
        mockRepository=new MockRepository();//1
        mockView = mockRepository.CreateMock<IView_SearchProject>();//2
    }
    [Test]
    public void GetDestUrl()
    {
        SearchRange range = new SearchRange(true, true, false, string.Empty);
        //3
        //
        Expect.Call(mockView.Range).Return(range) ;
        //UrlBase
        Expect.Call(mockView.UrlBase).Return("http://localhost");
        //SearchKey
        Expect.Call(mockView.SearchKey).Return("searchKey");
        
        //4
        mockRepository.ReplayAll();
        //5
        presenter = new Presenter_SearchProject(mockView);

string destUrlReturned = presenter.GetDesUrl();
        string destUrlExpected = "http://localhost/ProjectPage/ProjectControl.aspx?"
                  +"search=searchKey&name=True&key=True&description=False";
        //6
        Assert.AreEqual(destUrlExpected,destUrlReturned);
    }

IView_SearchProject mockView;
    MockRepository mockRepository;
    Presenter_SearchProject presenter;

[TearDown]
    public void TestCleanup()
    {
        mockRepository.ReplayAll();
        mockRepository.VerifyAll();
    }

}

1. Rhion.Mock框架中要使用mock的对象都需要从MockRepository 这个对象中产生,它充当一个对象工厂的角色。
  2. 这一步就是创建我们使用的mock的对象了,需要以被mock类的类型作为泛型参数。
  3. 这一步的3行代码是真正mock的部分,它们分别对应着对mockView的三次调用。
    Expect.Call(mockView.Range).Return(range) ;
    Expect.Call表示我们希望调用mockVIew的那个方法,也包括属性。

.Return的意思我们打算让这个模拟对象返回什么样的值

综合起来的意思就是:我们希望mockView的调用者在调用MockView的某一个方法(或属性)时返回一个有return标识的值
  4. ReplayAll的调用千万不要忘掉,它的意思可以理解为,让之前设定的模拟行为生效,从此之后我们就可以把这个mock的对象当作是一个真是的对象来使用了。我觉得可以把它想像成CLR为我们自动生成了代码一样,为我们生成了一个对被mock对象的实现。
  5. 这一步是调用者对mock对象的使用。
  6. 测试我们关注的对象的行为是否正常

一个需要注意到地方

presenter = new Presenter_SearchProject(mockView);

像这样的初始化需要注意顺序,必须要等到MockView被真正模拟出来之后,也就是ReplayAll调用之后,因为在presenter 内部需要访问mockView的成员,比如:

range = view.Range;

但是如果你在mock对象调用者初始化的时候没有访问mock对象的成员,那么这样的初始化可以的。因为虽然mock对象的成员还米有mock出来,但是mock对象已经被生成了:

mockView = mockRepository.CreateMock<IView_SearchProject>();

只不过是个空壳:)

转载于:https://www.cnblogs.com/wxc-kingsley/p/8033545.html

Mock 入门,分析stub . mock区别相关推荐

  1. 快速入门JAVA单元测试——mock

    背景 为了确保代码的质量,对编写的代码进行单元测试是非常有必要的. 在JAVA项目中,一般的项目结构比较复杂.依赖众多.在微服务与spring boot大行其道的今天,单纯靠junit来进行单元测试一 ...

  2. Java注解@Mock和@InjectMocks及@Mock和@Spy之间的区别

    Java注解@Mock和@InjectMocks及@Mock和@Spy之间的区别 1.@Mock和@InjectMocks的区别 @Mock为您需要的类创建一个模拟实现. @InjectMocks创建 ...

  3. Google Mock 入门

    Google Mock 入门 原文 概述 什么是Mock? Mock,更确切地说应该是Mock Object.它究竟是什么?它有什么作用?在这里,我也只能先说说我的理解. 比如当我们在单元测试.模块的 ...

  4. android mock测试资源,Android 单元测试 --Mock 及 Mockito

    以前我在 Mock 概念 所谓的 Mock 就是创建一个类的虚假的对象,在测试环境中,用来替换掉真实的对象,主要提供两大功能: 验证这个对象的某些方法的调用情况,调用了多少次,参数是什么等等 指定这个 ...

  5. bean加载context idea_02-基于IDEA创建SpringBoot项目并进行入门分析

    SpringBoot 项目创建 创建Module 基于IDEA创建项目Module,模块名为04-springboot-start,组id和包名为com.cy,如图所示: 填写module信息,如图所 ...

  6. mysql thread入门分析

    MySQL thread入门分析 今天下午和群里的朋友讨论mysql的thread pool,讨论的非常热闹,收获不少,借此自己也总结下thread,以备忘.下面贴上lidan的图片: Mysql支持 ...

  7. mock模拟接口测试 vue_Easy Mock以及Vue+Mock.js模拟数据

    Easy Mock以及Vue+Mock.js模拟数据 一.Mock.js简介 Mock.js是一个可以模拟后端数据,也可以模拟增删改查操作的js库 基础语法规范 数据模板中的每个属性由 3 部分构成: ...

  8. 面向过程(或者叫结构化)分析方法与面向对象分析方法到底区别

    博主选的是老师给出的第一个议题"面向过程(或者叫结构化)分析方法与面向对象分析方法到底区别在哪里?",首先来讨论一下二者的定义. 结构化方法的基本思想是将待解决的问题看作一个系统从 ...

  9. Mockito3.8 如何mock静态方法 (如何mock PageHelper)

    项目中遇到需要mock PageHelper,因为用到了startPage方法,而此方法是静态方法,如果需要mock静态方法,网上说法比较多的都是需要用Powermock,而这就需要引入新的依赖,这样 ...

  10. socket入门分析

    socket入门分析 一.基于TCP的客户端与服务器端 1.服务器端 初始化socket,绑定特定端口或地址(bind),开始监听(listen),调用accept()d等待客户端请求.接收到客户端请 ...

最新文章

  1. 全球支付平台paypal社招一面,二面合并面经
  2. 【WPF】代码触发Button点击事件
  3. 自动化运维工具Puppet(管理资源)
  4. DC/DC电源模块介绍
  5. WinForm中Combobox绑定值问题
  6. svn update -r m path 代码还原到某个版本(这样之前的log日志也就没了,也就是清空log日志)...
  7. php hbase thrift,PHP使用Thrift操作Hbase
  8. Python一行代码给儿子制作九九乘法表
  9. java模拟数据库压测_Jeecgboot Feign、分布式压测、分布式任务调度
  10. Tomcat的下载与安装
  11. linux 2.6.32 sdxc 补丁,在大于32GB或64GB容量的SD卡上使用NOOB安装树莓派
  12. 主管都在用项目管理Excel表格模板管理项目
  13. 统计学(第七版)贾俊平课后习题数据
  14. VBA写一个下拉复选框,以及循环判断,附代码
  15. 计算机uc,UC浏览器
  16. SegeX SgxVariantArrayT:VC封装支持多维数组的变体类型(VRIANT 、SafeArray)(附免费免积分源代码)
  17. ubuntu中trusted.gpg文件有什么作用
  18. mysql 内存 优化_MySQL核心参数优化(内存优化)
  19. 当WebRTC Pion示例无音频流的时候,如何添加音频模块并通过浏览器播放?
  20. MKL FFT简单调试

热门文章

  1. 51单片机开发入门(1)-单片机简介
  2. 使用NOPI做Excepl导入导出
  3. 机器学习-DBSCAN密度聚类
  4. 安川机器人焊枪切换设定方法_安川机器人工具、用户、安全模式设定方法
  5. android 9坚果r1,坚果R1、小米MIX2S、一加6对比评测 骁龙845旗舰怎么选?
  6. 基于51单片机的电容电感电阻RLC测量仪protues仿真
  7. 个人业务网站php源码,最新个人发卡网源码,PHP运营级个人自动发卡平台完整源码...
  8. maven 打包命令的使用
  9. Hadoop面试题及参考答案
  10. 笔记本win10 1709 安装 v4w的教程