zoukankan      html  css  js  c++  java
  • 单元测试_使用 Nmock 单元测试 .NET 业务对象

    使用Nmock单元测试 .NET 业务对象

    Nmock是在开发环境下测试复杂业务对象的唯一方式

    理解单元测试问题

    在一个测试驱动的开发环境(test-driven developmentenvironment)下,为复杂的业务对象编写单元测试脚本很困难,因为,业务对象可能外部依赖(高耦合,high coupling)很多其他对象。

    有时,对于有限的项目预算来说,建立开发环境,并配置它们的单元测试,不大可能。但是开发人员可以通过 mock 测试对象解决这个问题。

    通过创建 mock 业务对象,而不是你复杂业务对象的真正实现,你可以一次测试一个类。Mock 对象是模拟对象,复制你的业务对象的行为,你可以在你真正的单元测试脚本中使用 这些mock 对象。

    使用 Nmock

    很少有微软 .NET 支持的模拟(mock)测试框架——Nmock 就是其中之一。Nmock 也可以很容易与 Nunit 测试框架集成。Nmock 是免费的。

    Nmock是一个独特的具有以下特征的模拟测试库:

    • 同其他单元测试框架一样,开发人员需要定义期望。你期待什么作为输出
    • 模拟对象基于实现的接口,本质上是动态的。
    • 如果实际的输出与预期不符合,那么你的测试用例将失败。
    • 错误信息显示错误的详细描述。

    安装 Nmock 测试环境

    为了开发示例应用程序,使用 VisualStudio 2008 .NET 框架3.5。单元测试使用 NUnit 2.5.10。在安装NUnit msi包之后,除了能看到 nunit.framework.dll的引用,还能看到nunit.mocks.dll,但本示例项目中只引用 nunit.framework.dll

    下载 Nmock 库,解压后,会得到一些 DLL 文件。在本示例项目中,只增加 NMock2.dll 的引用。本例演示常见的长度和距离的转换系数,将一个长度计量单位转换到另一个的转换系数。例如,米到英尺的转换系数是3.28

    首先创建一个C#控制台程序。新建接口 IconversionService,代码如下:

       1:  using System;
       2:  using System.Collections.Generic;
       3:  using System.Text;
       4:   
       5:  namespace MockTesting.Sample
       6:      {
       7:      public interface IconversionService
       8:          {
       9:          double GetConversionRate ( string fromlength, string tolength );
      10:          }
      11:   
      12:      }

    说明:GetConversionRate 方法返回转换因子。

    新建类 ConversionServices,代码如下:

       1:  using System;
       2:  using System.Collections.Generic;
       3:  using System.Text;
       4:   
       5:  namespace MockTesting.Sample 
       6:      {
       7:      public class ConversionServices : IconversionService
       8:          {
       9:      
      10:         public double GetConversionRate ( string fromlength, string tolength )
      11:              {
      12:              if ( fromlength.Length <=0 || tolength.Length <= 0 )
      13:                  return 0;
      14:   
      15:                switch(fromlength)       
      16:                {         
      17:                   case "MET":   
      18:                      if (tolength.Trim().ToString() == "FT" )
      19:                          return 3.28;
      20:                      break;                  
      21:                   case "FT":            
      22:                         if (tolength.Trim().ToString() == "MET" )
      23:                             return 0.3048;
      24:                       break;
      25:   
      26:                   case "MILE":
      27:                       if ( tolength.Trim ( ).ToString ( ) == "KM" )
      28:                           return 1.609344;
      29:                       break;
      30:   
      31:                   case "KM":
      32:                       if ( tolength.Trim ( ).ToString ( ) == "MILE" )
      33:                           return 0.621371192;
      34:                       break;
      35:                   default:            
      36:                      return 0;         
      37:                            
      38:                 }
      39:                return 0;
      40:              }
      41:         
      42:          }
      43:      }

    新建ConvertTotalValue 类,代码如下:

       1:  using System;
       2:  using System.Collections.Generic;
       3:  using System.Text;
       4:   
       5:  namespace MockTesting.Sample
       6:      {
       7:      public class ConvertTotalValue
       8:          {
       9:          private readonly IconversionService conversionService;
      10:   
      11:          public double ConvertTotal ( string fromlength, string tolength, double totvalue )
      12:              {
      13:              if ( fromlength.Trim ( ).Length <=0 || tolength.Trim ( ).Length <=0 )
      14:                  return 0;
      15:              if ( totvalue == 0 )
      16:                  return 0;
      17:              return conversionService.GetConversionRate ( fromlength, tolength ) * totvalue;
      18:              }
      19:   
      20:          public ConvertTotalValue ( IconversionService conversionService )
      21:              {
      22:                  this.conversionService = conversionService;
      23:              }
      24:          }
      25:      }

    说明:ConvertTotalValue 类里有一个只读的实例 IconversionService 接口,在其构造函数里实例化。那么这个实例就可以看作是一个 mock

    使用Nmock库单元测试 .NET 业务对象(比较)

    下面,为了演示一般的单元测试(使用 NUnit 库)与模拟测试(使用 Nmock库 )的区别,在 ConversionServicesTest  类创建两个不同的测试方法。

    ShowCorrectLengthConversion 方法中,使用一个 ConversionServices类的对象,并调用GetConversionRate 方法获得转换系数。如果你 debug 一下 GetConversionRate方法,那么会发现程序的控制被转交给重构的GetConversionRate 函数。

    而在ShowCorrectLengthConversionWithMock 方法中,没有创建任何 ConversionServices类的实例获得转换系数。取而代之的是真正的实现,创建一个 IconversionService 接口的mock实例,用来在计算转换的值。通过Nmock库函数创建一个模拟(mock)对象。请参考下面的代码:

       1:  Expect.Once.On ( mockconversionService ).
       2:    Method ( "GetConversionRate" ).
       3:    With ( objLengthType.FromLength, objLengthType.Tolength ).
       4:    Will ( Return.Value ( 3.28 ) );

    Expect.Once.On将创建一个模拟(mock)实例。所以,调用参数为“MET”和“FT”的GetConversionRate方法时,会返回转换系数3.28。下面的代码显示完整的模拟测试代码:

       1:  using System;
       2:  using System.Collections.Generic;
       3:  using System.Text;
       4:   
       5:  using NUnit.Framework;
       6:  using NMock2;
       7:   
       8:  namespace MockTesting.Sample
       9:      {
      10:      [TestFixture]
      11:      public class ConversionServicesTest
      12:   
      13:          {
      14:          private Mockery mocks ;
      15:   
      16:          private IconversionService mockconversionService ;
      17:   
      18:          private ConversionServices objConversionServices = new
      19:   ConversionServices ( );
      20:          private ConvertTotalValue objConvertTotalValue;
      21:   
      22:          [SetUp]
      23:          public void SetUp ( )
      24:   
      25:              {
      26:   
      27:              mocks = new Mockery ( );
      28:   
      29:              mockconversionService = mocks.NewMock<IconversionService> ( );
      30:   
      31:              objConvertTotalValue = new ConvertTotalValue ( mockconversionService );
      32:   
      33:              }
      34:          [Test]
      35:   
      36:          public void ShowCorrectLengthConversion ( )
      37:              {
      38:       
      39:              LengthType objLengthType = new LengthType ( );
      40:              objLengthType.FromLength= "MET";
      41:              objLengthType.Tolength= "FT";
      42:              Assert.AreEqual ( objConversionServices.GetConversionRate ( 
      43:              objLengthType.FromLength, objLengthType.Tolength ), 3.28 );
      44:            
      45:              }
      46:          [Test]
      47:          public void ShowCorrectLengthConversionWithMock ( )
      48:              {
      49:                               
      50:               LengthType objLengthType = new LengthType ( );
      51:               objLengthType.FromLength= "MET";
      52:               objLengthType.Tolength= "FT";
      53:   
      54:               Expect.Once.On ( mockconversionService ).
      55:               Method ( "GetConversionRate" ).
      56:               With ( objLengthType.FromLength, objLengthType.Tolength ).
      57:               Will ( Return.Value ( 3.28 ) );
      58:   
      59:               Assert.AreEqual ( objConvertTotalValue.ConvertTotal ( objLengthType.FromLength,              
      60:               objLengthType.Tolength, 10.0 ), 32.8 );
      61:               mocks.VerifyAllExpectationsHaveBeenMet ( );
      62:   
      63:              }
      64:   
      65:          }
      66:      
      67:      }

    参考资料

    http://www.nmock.org/
    http://www.devx.com/DevXNet/Article/45071
    http://msdn.microsoft.com/en-us/magazine/cc163904.aspx 
  • 相关阅读:
    【Java Web开发学习】Spring加载外部properties配置文件
    【Java Web开发学习】Spring4整合thymeleaf视图解析
    快速入门系列--MVC--06视图
    快速入门系列--WebAPI--03框架你值得拥有
    快速入门系列
    iOS 自己封装的网络请求,json解析的类
    iOS 本地通知
    iOS8 自定义navigationItem.titleView
    iOS8 UICollectionView横向滑动demo
    基于Spring开发
  • 原文地址:https://www.cnblogs.com/liuning8023/p/2131471.html
Copyright © 2011-2022 走看看