四 232008
每个做单元测试的人都应该一种技术–MOCK~什么是MOCK?其实没什么神秘的,就是打桩~网上流行的一些.NET的mock框架有:NMock2,Rhino.Mocks等……
NMock2是ThoughtWorks维护的一个开源项目,不知道是不是ThoughtWorks的风格就是敏捷开发基本没有文档,网络上很难找到关于NMock2的文档。而且网上给的例子也很简单,简单到需要自己补充一些东西上去才能跑通。还是用官网上的那个例子:现在有一个银行系统,它实现了一个功能,就是允许两个同名帐户之间实现转账功能。但是很不巧的是,在两个帐户之间转账涉及到汇率的问题,而这个汇率又是天天变的,需要从一个外部的服务来实现的。简单来说就是:
一个接口:IAccountService,实现转账的功能
一个接口:ICurrencyService,实现获取汇率的功能
1 2 3 4 5 6 7 8 9 10 | public interface IAccountService { void TransferFunds(Account from, Account to, double amount); } public interface ICurrencyService { double GetConversionRate(string fromCurrency, string toCurrency); } |
一个类:Account,就是一个一个的帐户
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | public class Account { private double _balance; private string _name; private string _currency; public double balance { get { return _balance; } private set { _balance = value; } } public string name { get { return _name; } set { _name = value; } } public string Currency { get { return _currency; } set { _currency = value; } } public Account() { this.name = null; this.Currency = null; } public Account(string name, string currency) { this.name = name; this.Currency = currency; } public void Withdraw(double amount) { this.balance -= amount; } public void Deposit(double amount) { this.balance += amount; } } |
还有一个实现了IAccountService接口的AccountService类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class AccountService : IAccountService { private readonly ICurrencyService currencyService; public AccountService(ICurrencyService currencyService) { this.currencyService = currencyService; } public void TransferFunds(Account from, Account to, double amount) { from.Withdraw(amount); double conversionRate = currencyService.GetConversionRate(from.Currency, to.Currency); double convertedAmount = amount * conversionRate; to.Deposit(convertedAmount); } } |
这里我们就对ICurrencyService接口实现一个Mock,给测试程序传递一个假的对象
首先在NUnit的代码里面定义需要用到的对象
1 2 3 | Mockery mocks; ICurrencyService mockCurrencyService; IAccountService accountService; |
然后在单元测试的TestInitialize方法里面初始化mock
mocks = new Mockery(); //初始化mocks mockCurrencyService = mocks.NewMock<ICurrencyService>(); //产生一个mock对象 accountService = new AccountService(mockCurrencyService); //用mock对象初始化accountService
最后就是测试的代码:
public void ShouldUseCurrencyServiceToDetermineConversionRateBetweenAccounts() { //生成2个帐号 Account canadianAccount = new Account("John Doe", "CAD"); Account britishAccount = new Account("Jane Doe", "GBP"); //给英国人存100块 britishAccount.Deposit(100); Expect.Once.On(mockCurrencyService). Method("GetConversionRate"). With("GBP", "CAD"). Will(Return.Value(2.20));//对于mockCurrencyService对象,如果他的GetConversionRate方法被调用,而且参数分别是("GBP", "CAD"),那么就返回一个值2.20 accountService.TransferFunds(britishAccount, canadianAccount, 100); Assert.AreEqual((double)0, britishAccount.balance,0.00001); Assert.AreEqual((double)220, canadianAccount.balance,0.00001); mocks.VerifyAllExpectationsHaveBeenMet(); }
Related posts: