單元測試之Mock(Moq)
阿新 • • 發佈:2018-10-24
inter 商品 void 簡單 calc 不用 準備 targe ted
Mock翻譯為“嘲弄”,其實就是偽造一個對象用於測試。在單元測試中,被測試方法依賴於其他對象時,為了測試簡單一般“偽造”一個這個對象;這樣做的目的:
- 不用考慮依賴對象的復雜性(方便準備測試數據)
只專註測試被測試方法,不將單元測試擴充到測試依賴對象
打折算法測試
商場中的商品類:
public class Product { public int ProductID { get; set; } public string Name { get; set; } public string Description { get; set; } public decimal Price { get; set; } public string Category { set; get; } }
打折接口:
public interface IDiscountHelper {
decimal ApplyDiscount(decimal totalParam);
}
被測試的打折算法
public class LinqValueCalculator : IValueCalculator { private IDiscountHelper discounter; public LinqValueCalculator(IDiscountHelper discountParam) { discounter = discountParam; } public decimal ValueProducts(IEnumerable<Product> products) { return discounter.ApplyDiscount(products.Sum(p => p.Price)); }
顯然,被測試方法ValueProducts
依賴打折接口IDiscountHelper
,這裏通過偽造一個實現IDiscountHelper
接口的對象。
Moq功能介紹
- 創建偽造對象
Mock<IDiscountHelper> mock = new Mock<IDiscountHelper>();
- 設置偽造對象的方法
mock.Setup(m => m.ApplyDiscount(It.IsAny<decimal>()))
參數限制
t.IsAny<decimal>()
通過It
限制這裏列出幾個限制表達式 解釋 例子 It.Is 通過predicate返回bool值判斷限制測試 It.Is<decimal>(v => v == 0)
It.IsAny T類型的任意值 It.IsAny()
It.IsInRange T類型參數的值在範圍內或外(rangeKind參數決定) It.IsInRange<int>(1, 100, Range.Inclusive)
設置返回值
.Returns<decimal>(total => total);
構造單元測試
[TestClass]
public class UnitTest2 {
private Product[] createProduct(decimal value) {
return new[] { new Product { Price = value } };
}
[TestMethod]
[ExpectedException(typeof(System.ArgumentOutOfRangeException))]
public void Pass_Through_Variable_Discounts() {
// arrange
Mock<IDiscountHelper> mock = new Mock<IDiscountHelper>();
mock.Setup(m => m.ApplyDiscount(It.IsAny<decimal>()))
.Returns<decimal>(total => total);
mock.Setup(m => m.ApplyDiscount(It.Is<decimal>(v => v == 0)))
.Throws<System.ArgumentOutOfRangeException>();
mock.Setup(m => m.ApplyDiscount(It.Is<decimal>(v => v > 100)))
.Returns<decimal>(total => (total * 0.9M));
mock.Setup(m => m.ApplyDiscount(It.IsInRange<decimal>(10, 100,
Range.Inclusive))).Returns<decimal>(total => total - 5);
var target = new LinqValueCalculator(mock.Object);
// act
decimal FiveDollarDiscount = target.ValueProducts(createProduct(5));
decimal TenDollarDiscount = target.ValueProducts(createProduct(10));
decimal FiftyDollarDiscount = target.ValueProducts(createProduct(50));
decimal HundredDollarDiscount = target.ValueProducts(createProduct(100));
decimal FiveHundredDollarDiscount = target.ValueProducts(createProduct(500));
// assert
Assert.AreEqual(5, FiveDollarDiscount, "$5 Fail");
Assert.AreEqual(5, TenDollarDiscount, "$10 Fail");
Assert.AreEqual(45, FiftyDollarDiscount, "$50 Fail");
Assert.AreEqual(95, HundredDollarDiscount, "$100 Fail");
Assert.AreEqual(450, FiveHundredDollarDiscount, "$500 Fail");
target.ValueProducts(createProduct(0));
}
}
單元測試之Mock(Moq)