程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 一個超輕量級的測試平台

一個超輕量級的測試平台

編輯:關於.NET

有時候,在開發環境中測試核心業務職能,可能需要花很長而寶貴的時間。

幸運地是有很多簡單而且自動化的測試平台。盡管如此,這個操作卻不會總是能提供預期的結果。有時,它需要人為進行檢查和評價。

此外,在一個大型項目中,編譯幾十個類,每一點變動是非常耗費時間和精力的,自動測試將不會達到預期的行為。OBP控制台測試框架是一個非常簡單,輕量級的類庫,它用於測試你的業務對象,但它沒有一個像windows forms,web, silverlight 、WPF的圖形界面。

OBP控制台測試庫的主要目的是:在將代碼整合到相關項目中之前,檢查它的核心業務功能。

在測試類有下列行為:

在運行時,通過自定義屬性和反射找出測試類和測試方法

提供測試人員提供一個簡單菜單式的控制台的用戶界面

允許重復使用菜單(控制台上的)

便利地顯示的業務對象的集合,並能便利從中選擇單獨的業務對象進行測試。

文章中的一些定義

測試方法 :能通過執行一些動作來驗證開發項目的行為、動作、過程。

測試類 :是包含一個或多個測試方法的類。它也可能還包含測試類成員來執行重疊測試。

菜單 :是在控制台上顯示一系列的活動,允許測試人員使用鍵盤調用一個給定的測試方法。

結構:

整個類庫是建立在一個簡單的類上:CustomConsoleTest。這個類完成以下行動:

1、它使用反射浏覽所有子類的方法並找出有“TestMethod”屬性的方法。

2、使用“TestMethod”屬性,它能正確顯示在菜單上使用的方法的名稱。

測試時,簡化了業務對象集合的顯示,以及簡化在集合中選擇單獨的業務對象。

3、為了進行測試,你需要實例化一個CustomConsoleTest子類(這個類是抽象的)和調用方法“Execute”方法。

在這個簡單的類中,神奇之處是一個測試類可以嵌入其他的測試類,執行父類中的測試方法能調用子類的Execute方法。因此,你能很快建立一個分層控制台菜單,用於在整合之前專注於核心業務功能的測試。

實現:

所有的測試類都要繼承CustomConsoleTest。下面是構造函數:

CustomConsoleTest

public CustomConsoleTest()
         {
             var t = this.GetType();
             int i = 0;
             string name = null;
             // find the methods
             foreach (var m in t.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
             {
                 if (IsValidMethod(m, ref name))
                 {
                     var item = new MethodItem(name, m);
                     _methods.Add(_menuKeys[i], item);
                     ++i;
                 }
             }
         }

當CustomConsoleTest子類被實例化,執行以下操作:

1、使用反射去查找有自定義屬性TestMethod的方法。

2、當一個方法有TestMethod屬性,它被添加到一個類名為MethodItem的集合,這個集合包含MethodInfo實例和方法的名稱。

一旦測試方法發現,它將顯示在菜單上,允許測試人員通過鍵盤上的鍵調用的測試方法。

為了完成這些,測試人員必須調用方法“Execute”的方法,這個方法浏覽方法集合和在菜單上顯示測試方法友好名稱(如[TestMethod("List Machines")]中就顯示List Machines)。

為了重復的測試,因此能實現重復菜單,測試類可以嵌入其他測試類,調用測試方法也將調用嵌入類的"Execute"。代碼如下:

Execute

public void Execute()
         {
             char c = '*';
             while ((c != 'q') && (c != 'Q'))
             {
                 foreach (var p in _methods)
                     Console.WriteLine("{0} - {1}", p.Key, p.Value.DisplayText);
                 Console.WriteLine("q - Quit");
                 Console.WriteLine();
                 c = Console.ReadKey(true).KeyChar;
                 if (_methods.ContainsKey(c))
                     try
                     {
                         var m = _methods[c];
                         m.Method.Invoke(this, null);
                     }
                     catch (Exception ex)
                     {
                         Console.ForegroundColor = ConsoleColor.Red;
                         Console.WriteLine("An exception has occured when invoking the method {0}",
                             ex);
                     }
             }
         }

為了方便地顯示和選擇集合中的項,我添加一個泛型函數來簡化集合處理,這假設集合實現了通用接口IEnumerable<T>。

DisplayCollection

protected void DisplayCollection<T>(IEnumerable<T> aCollection)
{
     if (aCollection.Count() == 0)
         Console.WriteLine("No item in the collection");
     int i = 1;
     _elts.Clear();
     foreach (var e in aCollection)
     {
         Console.WriteLine("{0} - {1}", i, GetDescription(e));
         _elts.Add(i, e);
         ++i;
     }
     Console.WriteLine();
}

SelectItem方法使在控制台模式下選擇測試方法更加容易:

代碼

protected T SelectItem<T>(IEnumerable<T> aCollection) where T : class
         {
             DisplayCollection<T>(aCollection);

             while (true)
             {
                 Console.WriteLine("Type the element number or q to exit");
                 var text = Console.ReadLine();
                 if ((text == "q") || (text == "Q"))
                     return null;
                 try
                 {
                     int index = Convert.ToInt32(text);
                     if (_elts.ContainsKey(index))
                         return (T)_elts[index];
                     else
                         Console.WriteLine("The list does not contain that number, try again !");
                 }
                 catch
                 {
                     Console.WriteLine("Wrong value");
                 }
             }
         }

為了顯示菜單,我將尋找到的測試方法放在MethodItem類中

代碼

class MethodItem
     {
         internal MethodItem(string aDisplayText, MethodInfo aMethod)
         {
             DisplayText = aDisplayText;
             Method = aMethod;
         }
         internal string DisplayText { get; private set; }
         internal MethodInfo Method { get; private set; }
     }

示例:

將所有的功能展示在一個機器和零配件的示例中,應用程序包括兩種類型的業務對象:Machine(機器)和SparePart(零配件)。

代碼

class Machine : Asset
{
    //機器類中有添加零配件AddPart方法。CreateInstances靜態的構建方法,零配件列表:List<SparePart>
     internal void AddPart(SparePart aPart)
     {
         Parts.Add(aPart);
         AddWeight(aPart.Weight);
     }

     public Machine(string aName)
         : base(aName)
     {
         Parts = new List<SparePart>();
     }

     public static void CreateInstances()
     {
         Machines = new List<Machine>();
         for (int i = 0; i < new Random().Next(10) + 1; i++)
             Machines.Add(new Machine(string.Format("Machine{0}", i)));
     }

     public static List<Machine> Machines
     {
         get;
         private set;
     }

     public List<SparePart> Parts { get; private set; }
}

零配件類:

代碼

class SparePart : Asset
{
     public SparePart(Machine aMachine, string aName, double aWeight):
         base(aName)
     {
         Machine = aMachine;
         Weight = aWeight;
         aMachine.AddPart(this);
     }

     public static void CreateInstances()
     {
         Parts = new List<SparePart>();
         var random = new Random();
         foreach(var m in Machine.Machines)
             for (int i = 0; i < random.Next(5); i++)
             {
                 var part = new SparePart(m, string.Format
                     ("{0}-part{1}", m.Name, i),
                     random.NextDouble());
                 Parts.Add(part);
             }
     }

     public Machine Machine { get; private set; }

     public static List<SparePart> Parts
     { get; private set; }
}

要實現我的測試操作,我需要三個類:MachineTest測試Machine,PartTest測試spare部分,SoftwareTest中嵌入這兩個的測試。

代碼

/// <summary>
/// this class is used to test software
/// </summary>
class SoftwareTest : CustomConsoleTest
{
     /// <summary>
     /// machine test
     /// </summary>
     private MachineTest _machineTest = new MachineTest();

     /// <summary>
     /// part test
     /// </summary>
     private PartTest _partTest = new PartTest();

     [TestMethod("Machines")]        
     private void ExecuteMachineTest()
     {
         _machineTest.Execute();
     }

     [TestMethod("Parts")]
     private void ExecutePartTest()
     {
         _partTest.Execute();
     }

     static SoftwareTest()
     {
         Machine.CreateInstances();
         SparePart.CreateInstances();
     }
}

代碼

class MachineTest : CustomConsoleTest
{
     [TestMethod("List Machines")]
     private void ListMachines()
     {
         DisplayCollection<Machine>(Machine.Machines);
     }

     protected override string GetDescription(object e)
     {
         if(e is Machine)
         {
          var m = e as Machine;
          return string.Format("Machine {0} | {1:0.00} | Parts : {2}",
              m.Name, m.Weight, m.Parts.Count);
         }
         return base.GetDescription(e);
     }
}

為了更精細顯示的業務對象,我重寫的方法GetDescription,它本身是以ToString方法為基礎。

代碼

class PartTest : CustomConsoleTest
{
     protected override string GetDescription(object e)
     {
         if (e is SparePart)
         {
             var p = e as SparePart;
             return string.Format("Machine : 
                 {0} - {1}", p.Machine.Name, p.Name);
         }
         return base.GetDescription(e);
     }

     /// <summary>
     /// selection
     /// </summary>
     [TestMethod("Select A Part")]
     protected void TestSelect()
     {
         var p = SelectItem<SparePart>(SparePart.Parts);
         if (p != null)
             Console.WriteLine("You have selected the part {0}", p.Name);
     }
}

總結:

以我個人開發大型軟件系統的經驗,自動化測試是很好,但還往往不夠,在非常特別的情況,要耗很多時間去測試。我的做法很重要一點是沒有軟件界面部分,在控制台項目中進行測試非常的快。

出處:http://zhuqil.cnblogs.com

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved