標籤:
本文主要介紹Visual Studio(2012+)單元測試架構的一些技巧:
- 如何類比類的建構函式
- 最佳化代碼,便於測試
一、如何類比類的建構函式1.1 被測代碼
基礎代碼,IShape分別有Rectangle和Triangle倆個子類。有一個簡單的CalculateArea方法。
namespace BlogDemo.UTDemo{ public interface IShape { int CalculateArea(); } class Rectangle : IShape { public int CalculateArea() { return 1; } } class Triangle : IShape { public int CalculateArea() { return 100; } }}
被測試的類:該類根據傳入的參數不同而調用不同的子類進行操作。
class App { public void Calculate(string shapeType) { if (shapeType == "T") { new Triangle().CalculateArea(); } else { new Rectangle().CalculateArea(); } } }
1.2 測試目標
現在要測試App類的Calculatef方法,測試該類的case可以分成兩個
- 當輸入(shapeType)為T的時候執行個體化Triangle類。
- 當輸入為非T的時候執行個體化Rectangle類。
上面的測試主要是為了測試這個if的調度是否正確,而不關心Calculate到底做了什麼。所以上面測試的驗證不應該通過CalculateArea的值來進行驗證,因為這違反了單元測試的“單元”二字。
1.3 測試代碼
在ms.test架構下,可以通過ShimClassName.Constuctor來類比類名為ClassName的類的建構函式
[TestClass] public class AppTests { [TestMethod] public void CalculateTest() { using (ShimsContext.Create()) { var triangleConstructed = false; ShimTriangle.Constructor = (@this) =>//此處類比Triangle類的建構函式,如果Triangle被執行個體化,則triangleConstructed為true { triangleConstructed = true; }; var rectangleConstructed = false; ShimRectangle.Constructor = (@this) =>//此處類比Rectangle類的建構函式,如果Rectangle被執行個體化,則rectangleConstructed為true { rectangleConstructed = true; }; App.Calculate("T"); Assert.IsFalse(rectangleConstructed); Assert.IsTrue(triangleConstructed); } } }
因為App.Calculate("T");所以Triangle類被執行個體化(triangleConstructed為true),而Rectangle類沒有被執行個體化(rectangleCOnstructed為false)。
相反,得下面的測試結果:
[TestClass] public class AppTests { [TestMethod] public void CalculateTest() { using (ShimsContext.Create()) { var triangleConstructed = false; ShimTriangle.Constructor = (@this) =>//此處類比Triangle類的建構函式,如果Triangle被執行個體化,則triangleConstructed為true { triangleConstructed = true; }; var rectangleConstructed = false; ShimRectangle.Constructor = (@this) =>//此處類比Rectangle類的建構函式,如果Rectangle被執行個體化,則rectangleConstructed為true { rectangleConstructed = true; }; App.Calculate("F");//非T。Rectangle將會被執行個體化 Assert.IsTrue(rectangleConstructed); Assert.IsFalse(triangleConstructed); } } }
二、代碼最佳化。
在TTD中有一種說法叫做代碼不可測試,其實要不是ms.test架構的Shim功能強大,上面的代碼其實是不可測試的。上面的代碼完全可以進行最佳化。
2.1 最佳化後的代碼
public class App { public static void Calculate(string shapeType) { var shape = CreateShape(shapeType); shape.CalculateArea(); } public static IShape CreateShape(string shapeType) { if (shapeType == "T") { return new Triangle(); } else { return new Rectangle(); } } }
上面使用一個簡單工場先構建一個IShape對象,這樣這個構建過程以方法的形式公布出來,可以就這個CreateShape方法進行單獨測試。
2.2 最佳化後的測試代碼
[TestMethod] public void CreateShape_TriangleConstructed_Test() { var shape = App.CreateShape("T"); Assert.AreEqual(shape.GetType(), typeof(Triangle)); } [TestMethod] public void CreateShape_RectangleConstructed_Test() { var shape = App.CreateShape("F"); Assert.AreEqual(shape.GetType(), typeof(Rectangle)); }
簡單調整了一下代碼,測試代碼就變的非常簡單,且非常清晰,當然針對最佳化後的代碼之前使用Shim方式的測試代碼還是可以繼續啟動並執行。
三、結論
使用微軟的測試架構很多之前“不能測試”的代碼依然可以繼續測試,但是這不是好習慣,測試不應該過於依賴測試架構的feature。而是應該在測試的過程中慢慢調整代碼,讓代碼變的可“測試”。
Unit Test Via Visual Studio-Part4