這幾天有一個小工具需要做測試,是一個命令列工具,這個命令列工具有點類似mdbg等命令列工具,即程式運行後,在命令列等待使用者敲入的命令,處理命令並顯示結果,再繼續等待使用者敲入新的命令。
原來的測試案例都是手工執行的,即在測試文檔裡寫明輸入什麼命令,期望得到什麼結果之類的。這種手工的工作當然要自動化執行才行。
但是自動化測試這個工具有一個問題,因為這個工具不象其他的命令列程式—接受一些命令列參數,處理一下並顯示結果,然後退出。而是在命令列不斷地接受新的指令,處理並回顯,再接受使用者新的命令。因此不能用普通的 批處理的方式來執行測試。
要對這種程式執行自動化測試,主要是利用到每個進程啟動時,實際上都是有三個預設已經開啟的檔案,標準輸入(Standard Input)、標準輸出(Standard Output)和標準錯誤輸出(Standard Error)。對於命令列程式來說,標準輸入就是鍵盤,標準輸出就是電腦螢幕,預設情況下,標準錯誤輸出和標準輸出使用的是同一個檔案(在現代作業系統中,所有的裝置都被看成檔案,不光光是Linux, Unix這麼處理,其實Windows也是這麼處理的)。
進程的標準輸入、輸出以及錯誤輸出在啟動進程之前實際上是可以更換的,這也就是處理序間通訊經常採用的一個技術—管道技術。即,你可以通過管道技術,將一個進程的標準輸入和另一個進程的標準輸出串連起來,這樣一個進程輸出一些資料後,另外一個進程就自動獲得這些資料。下面這個簡單的命令就是管道的一個應用:
dir | sort
上面的命令就是把dir命令的輸出的資料直接傳遞到sort的輸入中,這樣sort就可以進行相應的排序,過程如所示:
在Win32編程裡,使用管道稍微顯得麻煩點,但是在.NET裡,替換和關閉進程的標準輸入、輸出和錯誤輸出都是相當簡單的工作。假設下面這個程式是我們即將測試的命令列程式,它的工作很簡單,就是不停地回顯使用者在命令列輸入的字串,最後使用者敲擊空格時,退出程式執行:
|
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication
{
public class Program
{
public static void Main()
{
string command = null;
do
{
Console.Write(">");
command = Console.ReadLine();
Console.WriteLine();
command = command.TrimEnd();
Console.WriteLine("Hello: {0}", command);
}
while (!string.IsNullOrEmpty(command));
Console.WriteLine("Quiting ...");
}
}
} |
下面是自動化測試程式,它的工作就是開啟待測得命令列程式,使用管道技術向待測程式的標準輸入傳遞命令,然後從待測程式的標準輸出讀取結果:
|
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace CmdTest
{
class Program
{
static void Main(string[] args)
{
if (args.Length != 1)
{
Console.WriteLine("Usage: CmdTest <Application>");
return;
}
var cmd = args[0];
var startinfo = new ProcessStartInfo(cmd);
startinfo.UseShellExecute = false;
startinfo.RedirectStandardInput = true;
startinfo.RedirectStandardOutput = true;
startinfo.RedirectStandardError = true;
var process = new Process();
process.StartInfo = startinfo;
process.Start();
var names = new string[] {
"Yimin",
"Zhang San",
"Li Si",
"Wang Wu"
};
foreach (var name in names)
{
process.StandardInput.WriteLine(name);
process.StandardInput.Flush();
// Skip the echo characters
process.StandardOutput.ReadLine();
var result = process.StandardOutput.ReadLine();
if (result != string.Format("Hello: {0}", name))
Console.WriteLine("Error!");
}
process.StandardInput.WriteLine();
process.WaitForExit();
}
}
} |