.Net单元测试(四)——Mock对象

来源:互联网 发布:nginx 自定义header 编辑:程序博客网 时间:2024/05/22 00:38


Why mock

     由于做单元测试针对大到具体类,小到某个方法的测试,试想一下:如果你要测的类或者方法,强依赖于另一个项目中的接口或是参数。例如在高校平台中,权限系统需要实现控制基础、考试、新生各系统,不可避免的要调用别的系统接口。

测试时,基础系统的接口,权限人员是未知的,调用该接口,一旦出错,便开始找各种原因,是我自己的方法写错了?是基础接口的问题吧?所以当这种类之间、接口之间的依赖关系导致我们无法顺利地进行测试,甚至无法顺利的完成编码时,mock应运而生了。

What is mock

简单来说,mock充当的就是替身的工作。举个简单的例子,比如A方法的实现需要B方法传必要的参数(AB相互依赖),当为A方法作单元测试时,为避免由B方法传参错误的外部原因而引发的A方法执行失败的问题,我们用mock对象来替代B方法,给A传入我们可控的参数类型或数量,从而排除A执行失败的外部原因,达到对A进行单元测试的目的。所以使用mock对象来解除被测类与其他类间的依赖问题,达到对某单一对象进行单元测试的目的。

How to use mock

使用Mock进行测试的关键三步骤:

  1. 使用一个接口来描述被测对象

  2. 编写产品代码实现这个接口

  3. 以测试为目的,在mock对象中实现这个接口

下面我将用一个demo来阐述mock的具体使用。类图如下:

 

整个解决方案共五个类,分别存放在【ProductFile】产品代码文件夹和【TestFile】测试代码文件夹中。

【产品代码】

1、使用接口描述被测对象:

 public  interface Interface    {        //该接口共两个方法,Now:用于获取当前时间,PlayWavFile:到点播放音乐              DateTime Now               {                  get;             }                   void PlayWavFile(string p);    }

2、编写产品代码,实现该接口

public class ProductClass :Interface    {                //2、上述接口的两个具体实现                 public DateTime Now            {                get                {                    return DateTime.Now;                }            }          public void PlayWavFile(string p)            {                throw new NotImplementedException();            }

//接口的使用者,Checker类,调用接口方法    public class Checker    {       Interface inter;       public Checker (Interface inter)       {           this.inter = inter;       }       //调用接口Now方法,PlayWavFile方法       public void Reminder()       {           DateTime now = inter.Now ;           if (now.Hour >= 17)           {               inter.PlayWavFile("duang~.mp3");           }       }
【测试代码】
3、编写Mock对象实现该接口(起到替代产品代码ProductClass的作用)
public  class MockClass :Interface    {        //3、以测试为目的,在mock对象中实现这个接口          private  DateTime currentTime;                    public MockClass(DateTime when)            {                currentTime = when;            }        public DateTime Now            {                get                {                    return currentTime ;                }            }                       //根据测试需求加上分钟数,控制mock对象的返回值            public void IncreateMinutes(int minutes)            {                currentTime = currentTime.AddMinutes(minutes);            }                        private bool soundWasPlayed = false;            public void PlayWavFile(string fileName)            {                soundWasPlayed = true;            }                        public bool CheckAndReseetSound()             {                bool value = soundWasPlayed;                soundWasPlayed = false;                return value;            }
最终测试类【TestChecker】:
using NUnit.Framework;namespace MockTest{   [TestFixture]    public class TestChecker    {       [Test]       public void QuittingTime()        {           DateTime when = new DateTime(2015, 3, 7, 11, 10, 0);           MockClass mock;           mock = new MockClass(when);           Checker checker = new Checker(mock);           //测试reminder方法,正确时间应为11:10,使用断言判断返回时间是否正确           checker.Reminder();           Assert.IsFalse(mock.CheckAndReseetSound(), "11:10");           //调用mock对象IncreateMinutes方法,动态的控制reminder方法的传入参数           mock.IncreateMinutes(5);           checker.Reminder();           Assert.IsTrue (mock.CheckAndReseetSound(),"11:15");           mock.IncreateMinutes(10);           checker.Reminder();           Assert.IsTrue(mock.CheckAndReseetSound(), "11:20");       }    }}
使用Nunit测试结果(具体加载dll步骤,详见单元测试之Nunit):




 

 

0 0
原创粉丝点击