翻看自己以前寫的代碼,突然間看到以前模擬的一個自動化測試架構的實現。幸好自己有寫學習筆記的習慣,整理一下,貼出來,以備忘。
1. 利用反射機制,作為特性的元數據可以反過來在運行時影響代碼的運行配置項,(例如:Windows Form程序中[STAThread]和[MTAThread用於表明應用程序的線程模型是單線程單元還是多線程--是否可以這樣歸屬有待商榷)或者為特殊的操作方法以特性作標記,以便在運行時做特殊處理(在P/Invoke中DLLImport特性標記方法轉化為托管方法)。
2. 可以用於構建管理項目程序集工具:特性表現為某種特殊注釋,而注釋內容可以在編譯后從程序集(例如TestCaseClass.DLL)中讀取出來,從而可以通過特性內容的注釋和讀取實現對程序集中各種類型和方法進行管理(例如可以篩選特定特性的方法執行)。
2. 特性參數分為環境參數和命名參數,如果特性類有自己的構造函數,則參數是必選的,為命名參數;剩下的參數為命名參數。在特性中應用命名參數必須加上參數名稱。可以重載構造函數以滿足不同組合。
namespace AttributesClass { [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] public sealed class ClassCleanupAttribute:Attribute { public ClassCleanupAttribute() { } } } namespace AttributesClass { [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] public sealed class ClassInitializeAttribute:Attribute { public ClassInitializeAttribute() { } } } namespace AttributesClass { [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] public sealed class DescriptionAttribute:Attribute { private string description; public string Description { get { return this.description; } set { this.description = value; } } public DescriptionAttribute(string text) { this.description = text; } } } namespace AttributesClass { [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] public sealed class PriorityAttribute:Attribute { private int priorityLevel; public int Level { get { return this.priorityLevel; } set { this.priorityLevel = value; } } public PriorityAttribute(int level) { this.priorityLevel = level; } } } namespace AttributesClass { [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] public sealed class TestPropertyAttribute:Attribute { #region Fileds private string propertyName = null; private string propertyValue = null; #endregion #region Proerties public string Name { get { return this.propertyName; } set { this.propertyName = value; } } public string Value { get { return this.propertyValue; } set { this.propertyValue = value;} } #endregion #region Constructors public TestPropertyAttribute(string strPropertyName, string strPropertyValue) { this.propertyName = strPropertyName; this.propertyValue = strPropertyValue; } #endregion } }
查找TestProperty限定的方法,找到后查找所在類是否有ClassInitialize和ClassCleanup方法,如果有則先執行前者然后執行該方法最后執行后者。
public void RunTest(string name, string value) { List<string> selectedMethods = SearchMethodByTestProperty(name, value); foreach (string method in selectedMethods) { string[] strSplitMethod = method.Split('.'); string nameSpaceName = strSplitMethod[0]; string className = strSplitMethod[1]; string methodName = strSplitMethod[2]; Console.WriteLine(nameSpaceName + '.' + className); Console.WriteLine("-------------------------------------------------------"); Type typeClass = assmeblyObject.GetType(nameSpaceName + '.' + className); MethodInfo testMethod = typeClass.GetMethod(methodName); object classObject = assmeblyObject.CreateInstance(nameSpaceName+'.'+className); MethodInfo[] methodArray = typeClass.GetMethods(); foreach (MethodInfo objMethod in methodArray) { object[] classInitializeAttributes = objMethod.GetCustomAttributes(typeof(AttributesClass.ClassInitializeAttribute), true); if (classInitializeAttributes.Length == 1) { Console.WriteLine("You are invoking the classInitialize method..."); Console.WriteLine(objMethod.Name + @"() "); objMethod.Invoke(classObject, null); //InvokeIntialize(classObject, objMethod); } } //InvokeTestMethod(classObject, method); Console.WriteLine("You are invoking the Select method..."); Console.WriteLine(methodName + @"() "); testMethod.Invoke(classObject, null); foreach (MethodInfo objMethod in methodArray) { object[] classCleanupAttributes = objMethod.GetCustomAttributes(typeof(AttributesClass.ClassCleanupAttribute), true); if (classCleanupAttributes.Length == 1) { //InvokeCleanup(classObject, objMethod); Console.WriteLine("You are invoking the classCleanup method..."); Console.WriteLine(objMethod.Name + @"() "); objMethod.Invoke(classObject, null); } } Console.WriteLine(""); } }
模擬實現架構代碼筆記:
1. 特性定義應該為public Sealed 以避免繼承和便於命名空間外的類或函數調用(自定義特性通常情況下很少被繼承,並且定義好的特性大多數情況下還是命名空間外引用的)
2. 定義特性時應該使用[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]來指定該特性是用於標記方法,類還是成員變量特性的。
3. 別調用的測試類DemoTest由於會被主調用函數調用也應該聲明為public。
4. 約定測試程序集里所有方法種類一致便於管理.(倘若測試Assmbly里既有靜態方法又有非靜態方法的話,那么在主調用函數反射時必須考慮到不同種類的方法,invoke 時的不同,非靜態方法必須得先實例化才能invoke)
5. 該架構里所有方法都是非靜態的,主調用函數實現非靜態方法必須得先實例化一個類,顯然比較麻煩。 為什么不寫成非靜態的呢。(因為倘若用到某個類中的方法,必須默認得去調用Initialize和Cleanup函數[如果這些函數存在的話],如果用靜態方法的話就必須的自己去判定查找調用這些方法,顯然實現起來比較麻煩)
不足:
1 並沒有完成對多限定條件下的查詢方法
2 目前為止所有的測試方法必須不包含參數(包含參數的方法很容易實現,可以考慮在運行時XML傳遞參數)
3 PropertyDemoTest類結構不太清晰,可以考慮重構一下
4 可以增加更多的自定義特性完成更為復雜的操作
由於只是簡單模擬框架,實現功能較為簡單,更為復雜的功能可以以后再加,這個架構最大的好處是耦合度小,可擴展性強。
全部源碼可去csdn下載,連接:http://download.csdn.net/detail/fl815824/4340631
http://msdn.microsoft.com/zh-cn/library/f7ykdhsy(v=VS.80).aspx