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:

  1. 测试代码重构实例
  2. 用XSD自动生成XML对应的.NET实体类
  3. WebDriver测试失败后自动获取截图
  4. Linq to Object在测试中的应用
  5. 利用序列化和反序列化实现深拷贝

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">