摘录于Pro ASP.NET MVC3 Framework一书:
Unit Test里用到的Moq技术【在单元测试项目里面加入对Moq.dll的引用】
接口定义:
public interface IProductRepository
{
IEnumerable<Product> GetProducts();
}
接口的实现类:
public class FakeRepository : IProductRepository
{
//275M,数字后面加m或M,表示是decimal类型,128位
private Product[] products = new Product[] {
new Product() { Name = "Kayak", Price = 275M},
new Product() { Name = "Lifejacket", Price = 48.95M},
new Product() { Name = "Soccer ball", Price = 19.50M},
new Product() { Name = "Stadium", Price = 79500M}
};
public IEnumerable<Product> GetProducts()
{
return products;
}
public decimal GetTotalValue()
{
return products.Sum(e => e.Price);
}
}
另一接口:
public interface IPriceReducer
{
void ReducePrices(decimal priceReduction);
}
该接口的实现类:
public class MyPriceReducer : IPriceReducer
{
private IProductRepository repository;
//依赖于IProductRepository接口
public MyPriceReducer(IProductRepository repo)
{
this.repository = repo;
}
public void ReducePrices(decimal priceReduction)
{
foreach (var item in repository.GetProducts())
{
item.Price = Math.Max(item.Price - priceReduction, 1);
repository.UpdateProduct(item);
}
}
}
没有用Moq技术的单元测试用例:【需要项目中的FakeRepository类】
[TestMethod]
public void CorrectTotalReductionAmount()
{
//
FakeRepository repo = new FakeRepository();
decimal reductionAmount = 10;
decimal initialTotal = repo.GetTotalValue();
MyPriceReducer target = new MyPriceReducer(repo);
target.ReducePrices(reductionAmount);
Assert.AreEqual(repo.GetTotalValue(),
(initialTotal - (repo.GetProducts().Count() * reductionAmount))
);
}
用到Moq技术的单元测试用例:
[TestMethod]
public void CorrectTotalReductionAmount2()
{
Product[] products = new Product[] {
new Product() { Name = "Kayak", Price = 275M},
new Product() { Name = "Lifejacket", Price = 48.95M},
new Product() { Name = "Soccer ball", Price = 19.50M},
new Product() { Name = "Stadium", Price = 79500M}
};
//此时是不需要IProductRepository接口的实现类的,也就是项目中不用手写一个IProductRepository接口的实现类,Moq可以模拟一个这样的实现类,
Mock<IProductRepository> mock = new Mock<IProductRepository>();
//当调用IProductRepository中的GetProducts()方法时,返回products
mock.Setup(m => m.GetProducts()).Returns(products);
decimal reductionAmount = 10;
decimal initialTotal = products.Sum(p => p.Price);
//把Moq模拟的这个对象传给MyPriceReducer
MyPriceReducer target = new MyPriceReducer(mock.Object);
target.ReducePrices(reductionAmount);
Assert.AreEqual(products.Sum(p => p.Price),
(initialTotal - (products.Count() * reductionAmount)));
}
//以上数据源products是声明在一个测试方法中的,为了代码简洁,可以把products声明在这个测试类中【这样需要用到数据源的其他测试方法都可以引用它】,如:
[TestClass()]
public class MyPriceReducerTest
{
private IEnumerable<Product> products;
[TestInitialize]
public void PreInitialize()
{
products = new Product[] {
new Product() { Name = "Kayak", Price = 275M},
new Product() { Name = "Lifejacket", Price = 48.95M},
new Product() { Name = "Soccer ball", Price = 19.50M},
new Product() { Name = "Stadium", Price = 79500M}
};
}
}
属性[TestInitialize]:在运行每一个测试用例之前,都会先进行调用PreInitialize()方法