在.net中有幾種mock框架可供選擇,比如NMock,PhinoMocks,FakeItEasy和Moq。儘管Moq相對較新,但是它非常易用。不需要像傳統的Record/Replay。並且使用Moq在VS中可以得到智慧提示。學習成本也不高。
這篇文章我們介紹下如何使用Moq來mock吧。
假定我們要做一個計算器提供基本的算術運算和不同貨幣的轉換。
ICaculator介面定義如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CalculatorPkg
{
public interface ICalculator
{
int Add(int param1, int param2);
int Subtract(int param1, int param2);
int Multipy(int param1, int param2);
int Divide(int param1, int param2);
int ConvertUSDtoRMB(int unit);
}
}
假定人民幣轉美元的介面定義如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MoneyExchangeRatePkg
{
public interface IUSD_RMB_ExchangeRateFeed
{
int GetActualUSDValue();
}
}
下面是Calculator的實現類,其中人民幣轉美元的介面例項以建構函式引數的形式傳給Calculator類。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MoneyExchangeRatePkg;
namespace CalculatorPkg
{
public class Calculator : ICalculator
{
private IUSD_RMB_ExchangeRateFeed _feed;
public Calculator(IUSD_RMB_ExchangeRateFeed feed)
{
this._feed = feed;
}
#region ICalculator Members
public int Add(int param1, int param2)
{
throw new NotImplementedException();
}
public int Subtract(int param1, int param2)
{
throw new NotImplementedException();
}
public int Multipy(int param1, int param2)
{
throw new NotImplementedException();
}
public int Divide(int param1, int param2)
{
return param1 / param2;
}
public int ConvertUSDtoRMB(int unit)
{
return unit * this._feed.GetActualUSDValue();
}
#endregion
}
}
下面我們開始準備Calculator元件的測試環境,我們使用NUnit框架和Moq來做Mock。
您可以到http://www.nunit.org/獲得nunit,到http://code.google.com/p/moq/獲得moq框架的原始碼和dll檔案。
然後我們就可以建立測試專案,並新增nunit和moq的引用。
我們要mock匯率的介面,下面是mock的方法:
Mock<IUSD_RMB_ExchangeRateFeed> mockObject = new Mock<IUSD_RMB_ExchangeRateFeed>();
mockObject.Setup(m => m.GetActualUSDValue()).Returns(500);
IUSD_RMB_ExchangeRateFeed value = mockObject.Object;
對匯率介面的MOCK只需要三行程式碼,第一行宣告mock介面,第二行設定要mock方法的返回值,第三步通過Object屬性獲得mock的物件。
下面是完整的測試程式碼:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Moq;
using CalculatorPkg;
using MoneyExchangeRatePkg;
namespace CalculatorPkg.Tests
{
// 新增TestFixture標識類是測試類
[TestFixture]
public class CalculatorTester
{
// 定義mock的邏輯
private IUSD_RMB_ExchangeRateFeed prvGetMockExchangeRateFeed()
{
Mock<IUSD_RMB_ExchangeRateFeed> mockObject = new Mock<IUSD_RMB_ExchangeRateFeed>();
mockObject.Setup(m => m.GetActualUSDValue()).Returns(500);
return mockObject.Object;
}
// 測試divide方法
[Test(Description="Divide 9 by 3. Expected result is 3.")]
public void TC1_Divide9By3()
{
IUSD_RMB_ExchangeRateFeed feed = this.prvGetMockExchangeRateFeed();
ICalculator calculator = new Calculator(feed);
int actualResult = calculator.Divide(9,3);
int expectedResult = 3;
Assert.AreEqual(expectedResult, actualResult);
}
[Test(Description = "Divide any number by zero. Should throw an System.DivideByZeroException exception.")]
[ExpectedException(typeof(System.DivideByZeroException))]
public void TC2_DivideByZero()
{
IUSD_RMB_ExchangeRateFeed feed = this.prvGetMockExchangeRateFeed();
ICalculator calculator = new Calculator(feed);
int actualResult = calculator.Divide(9, 0);
}
[Test