共用方式為


本文章是由機器翻譯。

測試回合

使用通訊端進行 WCF 服務測試

Dr。James McCaffrey

在本月 ’s 專欄我正在聯結的卡洛斯 Figueira Windows 通訊基礎 (WCF) 小組在測試中一個資深軟體開發工程師。他協助我想告訴您如何測試 WCF 服務使用網路通訊端為主的方法。

才能看到我字形的其中一個好辦法,就是檢查在 螢幕擷取畫面數字 1,2 和 3。[圖 1 顯示 WinForm 應用程式裝載名為 MathService 一個簡單但代表 WCF 服務。在幕後 MathService 包含名為會接受兩個值的型別雙,然後會計算並傳回其總和加總的單一作業。

圖 1受測試的 WCF MathService 服務

圖 2 顯示典型的 WCF ASP.NET Web 應用程式用戶端會接受來自使用者的兩個值、 將那些兩個值傳送到 MathService 服務、 擷取來自該服務回應並在清單方塊控制項中顯示結果。

圖 2典型的 WCF ASP.NET 用戶端

圖 3 顯示執行 MathService 服務的功能性確認一個主控台應用程式測試控管。測試控管會傳送 SOAP 訊息直接使用網路通訊端的 MathService 接受來自該服務的回應,並比較預期的結果,與實際的結果來決定是通過或失敗。在測試案例 # 001 測試控管傳送 3.4 和 5.7 WCF 服務下測試,並接收預期值 9.1。# 002 的測試案例是故意、 假性的失敗,只是供示範之用。

在各 「 節我第一次簡短地說明受測 所示的 WCF 服務圖 1 以便瞭解哪些因素有相關建構 WCF 通訊端為基礎的測試自動化時。接下來簡要說明示範 Web 用戶端可為您提供一些見解當通訊端為主測試是比替代技術更適當。然後我解釋詳細程式碼,建立測試控管,以便您將能夠適應我提出此處以符合自己需求的技巧。本文假設您有中繼層級 C# 程式碼撰寫技術。

圖 3WCF 測試控管執行

WCF 服務測試

我可以使用 Visual Studio 2008 來建立受測試 WCF 服務。WCF 服務的相關不錯的功能之一就是它們可以以許多不同類型的應用程式裝載。我決定裝載 WCF MathService 服務在一個 WinForm 應用程式但技術我提出在這個發行項工作中使用 WCF 主控件的任何型別。

建立空的 WinForm 後, 我加入兩個按鈕控制項和一個清單方塊控制項。然後,表單] 定義的正下方我新增簡單宣告 WCF 服務所需的程式碼:

[ServiceContract]
   public interface IMathService {
   [OperationContract]
     double Sum(double x, double y);
   }

套用至介面的 ServiceContract 屬性會產生 WCF inteface 所需的所有程式碼。 如果您移動從 Web 服務的 WCF,您可以想像成類似於 WebMethod 屬性 OperationContract 屬性。 實作 WCF 服務是很簡單:

public class MathService : IMathService  {
  public double Sum(double x, double y) {
    double answer = x + y;
    return answer;
  }
}

使用就地的我 WCF] 水管我加入了 System.ServiceModel.dll.NET 組件的房屋 WCF] 功能至我的專案的參考。 然後我會新增使用兩個機碼包含在我的 WCF 服務所需的組件內的.NET 命名空間的陳述式:

using System.ServiceModel;
using System.ServiceModel.Description;

ServiceModel 命名空間保留 ServiceHost 類別與數個定義 WCF 繫結的類別。 說明命名空間保留 ServiceMetadataBehavior 類別我用來發行我的 WCF 服務的相關資訊。 接下來我會新增服務執行個體化邏輯至 Button1 控制項事件處理常式:

try {
  string address = 
    "http://localhost:8000/MyWCFMathService/Service";
  Uri baseAddress = new Uri(address);
  serviceHost = 
    new ServiceHost(typeof(MathService), baseAddress);
  serviceHost.AddServiceEndpoint(typeof(IMathService),
    new WSHttpBinding(SecurityMode.None), "MathService");
  . . .

請注意此處索引鍵的因素是我建立了使用 WSHttpBinding 的 WCF 端點。 WCF 繫結是包括 secutity 和 reliabilty 設定、 傳輸通訊協定及編碼類型的相關資訊的集合物件。 WSHttpBinding 是雙工通訊的極佳的一般用途繫結。 預設情況下,WSHttpBinding 使用加密的傳輸,但此處我指定 SecurityMode.None,您就可以更容易看到要求-回應資料。

接下來我加入程式碼,讓我的服務可以看到用戶端透過加入服務參考機制:

ServiceMetadataBehavior smb = 
  new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
serviceHost.Description.Behaviors.Add(smb);
. . .

現在我 ’m 準備好要加入啟動 WCF 服務的程式碼:

serviceHost.Open();
int count = 0;
while (serviceHost.State != 
       CommunicationState.Opened && 
       count < 50) {
  System.Threading.Thread.Sleep(100);
  ++count;
}
. . .

我使用一種簡單但是有效的方法,可由即將進入的 0.1 秒最多的 50 延遲的延遲的 delay 迴圈偵測在啟動的服務擱置。 結束 delay 迴圈之後可能是 WCF 服務已啟動,或達到延遲最大數目:

if (serviceHost.State == CommunicationState.Opened)
  listBox1.Items.Add("WCF MathService is started");
else
  throw new Exception(
    "Unable to start WCF MathService in a timely manner");

我採取許多時撰寫實際執行程式碼如不檢查,看看 serviceHost 物件是否已經開啟嘗試開啟它之前 wouldn’t 採取的捷徑。 Button2 控制項事件處理常式中的邏輯關閉 WCF MathService,而且我使用該相同的模式來啟動服務:

int count = 0;
serviceHost.Close();
while (serviceHost.State != 
       CommunicationState.Closed && 
       count < 50) {
  System.Threading.Thread.Sleep(100);
  ++count;
}

典型的 Web 應用程式用戶端

我用來建立 WCF Web 應用程式用戶端 所示的 Visual Studio 2008圖 2. 我開始依序按一下 [檔案 | 新增 | 的 Web 站台。 在 [新的 [網站] 對話方塊中,我目標 Microsoft.NET Framework 3.5、 選取 [空白網站] 範本、 選擇了使用 C# 語言的檔案系統位置及命名為我的專案 WCFMathServiceWebClient。

接下來,在 [方案總管] 我用滑鼠右鍵按一下我的專案並從內容功能表選取 [加入新項目] 選項。 在 [結果] 對話方塊中,我選取 Web Form 項目。 我取消選取 「 將程式碼置於個別檔案 」 選項,因此我可以將所有我的應用程式程式碼放在單一檔案。

加入 Web Form 之後,我新增伺服器端控制項的標籤,來建立的 Web 應用程式非常簡單的使用者介面:

<asp:Label ID="Label1" runat="server" 
  Text="Enter first number: "/>
<asp:TextBox ID="TextBox1" runat="server" /><p />
<asp:Label ID="Label2" runat="server" 
  Text="Enter second number: "/>
<asp:TextBox ID="TextBox2" runat="server" /><p />
<asp:Button ID="Button1" runat="server" Text="Compute Sum" 
  onclick="Button1_Click" /><p />
<asp:ListBox ID="ListBox1" runat="server" />

接下來,我點擊 F5 鍵,以指示 Visual Studio 建置應用程式,並提示我允許自動產生的 Web.config 檔為我的專案。 之後我 OK’d 建立 Web.config 檔,我開始 WCF MathService 服務,所以我用戶端專案就能看到的服務。

我用滑鼠右鍵按一下方案總管] 中的用戶端專案,並從內容功能表選取 [加入服務參考] 選項。 在 [加入服務參考] 對話方塊中,我輸入我的 WCF 服務的位置 (http://localhost:8000/ MyWCFMathService / 服務),按一下 [Go] 按鈕。 因為我的 WCF 服務正在執行,而且該服務發佈有關本身的中繼資料 Visual Studio 工具將會發現該服務。 我重新命名服務命名空間與預設 ServiceReference1 到 WCFMathServiceReference。

在幕後 Visual Studio 會將 WCF 服務的相關資訊藉由建立一個 <system.serviceModel> 項目加入至 Web.config 檔。 項目包含 <endpoint>的項目與屬性繫結 = 」 wsHttpBinding 」,讓 Web 應用程式用戶端知道如何與 WCF 服務通訊。 在 [設計] 檢視我註冊其事件處理常式的 [Button1] 控制項上按兩下,然後加入邏輯,以存取服務:

try {
  WCFMathServiceReference.MathServiceClient sc =
    new WCFMathServiceReference.MathServiceClient();
  double x = double.Parse(TextBox1.Text);
  double y = double.Parse(TextBox2.Text);
  double sum = sc.Sum(x, y);
  . . . 
  ListBox1.Items.Add(
    "The response from the WCF service is " + sum);

保留加總作業類別的名稱是 MathServiceClient — 亦即類別 (MathService) 的名稱衍生自 WCF 合約介面 (IMathService) 與 「 用戶端 」 附加。

測試控管

我也會用來建立 C# 主控台應用程式專案命名 WCFTestHarness 的 Visual Studio 2008。 Visual Studio 產生 Program.cs 檔案的最頂端我新增這些使用陳述式:

using System;
using System.Text; 
using System.Net; 
using System.Net.Sockets;

我需要 System.Text 將文字轉換成位元組陣列,因為 TCP 運作在位元組層級的命名空間中的類別。 我需要 System.Net 命名空間來建立的 IP 位址的抽象概念的物件中的類別。 而且我需要 System.Net.Sockets 命名空間來建立通訊端物件,會執行實際的傳送和接收作業。 我 Main 方法中加入簡短的記錄訊息,並再設定我的測試案例資料,以字串陣列:

namespace WCFTestHarness {
  class Program {
    static void Main(string[] args) {
      try {
        Console.WriteLine(
        "\nBegin WCF MathService testing via sockets run");

        string[] testCases = new string[] {
          "001,3.4,5.7,9.1",
          "002,0.0,0.1,1.0",
          "003,6.7,6.7,13.4"
        };
        . . .

每個測試案例資料字串包含四個以逗號分隔的欄位:測試案例識別碼,加總] 操作並為預期的回應值的兩個輸入。 我使用我的測試案例資料來建立主要的測試控管處理迴圈:

foreach (string testCase in testCases) {
  Console.WriteLine("\n============\n");
  string[] tokens = testCase.Split(',');
  string caseID = tokens[0];
  string input1 = tokens[1];
  string input2 = tokens[2];
  string expected = tokens[3];
  . . .

我使用分割方法分成四個欄位的每個字串。

接下來是傳送給 WCF 服務使用通訊端輸入索引鍵部份的其中一個。 我建立如 所示的 SOAP 訊息圖 4.

圖 4進行測試 WCF 服務的 SOAP 訊息

string soapMessage = "<s:Envelope xmlns:s='http://www.w3.org/2003/05/soap-envelope'";
soapMessage += " xmlns:a='http://www.w3.org/2005/08/addressing'><s:Header>";
soapMessage += "<a:Action s:mustUnderstand='1'>http://tempuri.org/IMathService/Sum</a:Action>";
soapMessage += "<a:MessageID>urn:uuid:510b1790-0b89-4c85-8015-d1043ffeea14</a:MessageID>";
soapMessage += "<a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>";
soapMessage += "</a:ReplyTo><a:To s:mustUnderstand='1'>";
soapMessage += "http://localhost:8000/MyWCFMathService/Service/MathService</a:To></s:Header>";
soapMessage += "<s:Body><Sum xmlns='http://tempuri.org/'>";

soapMessage += "<x>" + input1 + "</x>" + "<y>" + input2 + "</y>";

soapMessage += "</Sum></s:Body></s:Envelope>";

請注意我的測試案例輸入的值、 input1 和 input2,嵌入 SOAP 訊息,訊息結尾附近的 <sum>項目內。 但沒有我要如何判斷這個不讓簡單訊息結構呢?

有幾種方式,您可以決定所需的 SOAP 訊息結構以及 WCF 服務的資料。 最簡單的方式,我使用另一個是使用如 netmon 或 Fiddler 的網路流量的檢查工具來擷取資料,雖然練習用戶端應用程式。 亦即與執行,我的 WCF 服務和資料傳輸擷取工具也執行 (我用 Fiddler,) 我啟動 所示的 Web 應用程式用戶端程式圖 2,用來傳送要求給 WCF 服務的用戶端。 網路資料傳輸擷取工具示範我已從用戶端傳送到 WCF 服務的 SOAP 訊息。 我可以使用該資訊來製作 SOAP 訊息在我的測試控管中。

與建構我 SOAP 訊息,接下來我顯示為預期的資料到殼層輸入我測試案例:

Console.WriteLine(
  "Test Case   : " + caseID);
Console.WriteLine(
  "Input       : <s:Envelope..." + "<x>" +
  input1 + "</x>" + "<y>" + input2 + 
  "</y>...</s:Envelope>");
Console.WriteLine("Expected    : " + expected);

然後我設定 IP 位址的目標受測的 WCF MathService 服務:

string host = "localhost";
   IPHostEntry iphe = Dns.Resolve(host);
   IPAddress[] addList = iphe.AddressList;
   EndPoint ep = new IPEndPoint(addList[0], 8000);

Dns.Resolve 方法會傳回特定的主機電腦名稱作為 IPHostEntry 物件相關聯的 IP 位址 (可能不只一個) 清單。 IPHostEntry 物件具有 AddressList 屬性是 IPAddress 物件的陣列。 端點物件包括 IPAddress 物件加上一個連接埠號碼。 現在我可以建立我通訊端:

Socket socket = new Socket(AddressFamily.InterNetwork,
  SocketType.Stream, ProtocolType.Tcp);
socket.Connect(ep);
if (socket.Connected)
  Console.WriteLine(
    "Connected to socket at " + ep.ToString());
else
  Console.WriteLine(
    "Error: Unable to connect to " + ep.ToString());

通訊端物件實作是抽象的機制來傳送及接收的網路流量在柏克萊通訊端介面。 通訊端的建構函式的第一個引數指定定址配置。 在此我使用是普通的 IPv4 的網路。

通訊端建構函式的第二個引數會指定您想要建立的六個可能的通訊端類型中的哪一種。 資料流表示 TCP 通訊端。 其他常見的型別是用於 UDP (使用者資料包通訊協定) 通訊端的 Dgram。

通訊端建構函式的第三個引數指定的通訊協定所支援的通訊端。 Socket.Connect 方法接受端點物件。

接下來我建構我標頭的資訊:

string header = 
  "POST /MyWCFMathService/Service/MathService HTTP/1.1\r\n";
header += "Content-Type: application/soap+xml; charset=utf-8\r\n";
header += "SOAPAction: 'http://tempuri.org/IMathService/Sum'\r\n";
header += "Host: localhost:8000\r\n";
header += "Content-Length: " + soapMessage.Length + "\r\n";
header += "Expect: 100-continue\r\n";
//header += "Connection: Keep-Alive\r\n\r\n";
header += "Connection: Close\r\n\r\n";

就像與 SOAP] 訊息我由標頭資訊使用監視工具的網路流量。 請注意每一行結尾為 \r\n (換行字元、 換行) 結束字元,而不是單一 \n (新行) 語彙基元,而且最後一行結尾為雙精度浮點 \r\n。 當我指示的註解上面的程式碼行,數目因素而定您可能需要將一個保持活動或是關閉的引數傳送給連線標頭項目。 同樣地,不需要為一個 WSHttpBinding SOAPAction 標頭。

現在我可以結合標頭和 SOAP 訊息,將整個訊息轉換成位元組,並將要求傳送:

string sendAsString = header + soapMessage;
byte[] sendAsBytes = Encoding.UTF8.GetBytes(sendAsString);
Console.WriteLine("Sending input to WCF service");
int numBytesSent = socket.Send(sendAsBytes, sendAsBytes.Length,
  SocketFlags.None);

Socket.Send 方法有數個多載。 此處我傳送整個要求沒有任何特殊傳送或接收的選項。 請勿進行使用傳回值,但我也可以使用該值來檢查我的整個訊息已傳送。 現在我可以擷取從 WCF 服務回應:

byte[] receivedBufferAsBytes = new byte[512];
string receiveAsString = "";
string entireReceive = "";
int numBytesReceived = 0;

while ((numBytesReceived =
  socket.Receive(receivedBufferAsBytes, 512,
  SocketFlags.None)) > 0) {
  receiveAsString =
    Encoding.UTF8.GetString(receivedBufferAsBytes, 0,
    numBytesReceived);
  entireReceive += receiveAsString;
}

因為在大多數情況下無法預測將會在回應的位元組數目,概念就是建立一個緩衝區,直到消耗整個回應讀取區塊 (Chunk) 回應。 在此我使用 512 大小的緩衝區。 在接收 512 位元組的每個群組它們會轉換成文字,並附加至彙總結果字串。

接收到的回應與我檢查回應,以查看若它會包含目前的測試案例預期的值:

Console.WriteLine("Response received");
if (entireReceive.IndexOf(expected) >= 0)
  Console.WriteLine("Test result : Pass");
else
  Console.WriteLine("Test result : **FAIL**");

我在這裡使用的方法是非常簡單的測試案例有效,但您也可以加入額外的邏輯,如果您的測試案例是變得更加複雜。 我就完成了佔用 loose 結束我控管:

. . . 
        } // main loop
        Console.WriteLine(
          "\n=======================================");
        Console.WriteLine("\nEnd test run");
      } // try
      catch (Exception ex)
      {
        Console.WriteLine("Fatal: " + ex.Message);
      }
    } // Main()
  } // Program
} // ns

總結

有許多的替代方案至 WCF 測試,不過通訊端為主的方法測試 WCF 服務是非常有彈性。因為 TCP 和通訊端是低階的語法結構,它們在許多情況下,特別的是您正在測試 technologically 異質性環境中。比方說您可以測試從非 Windows 用戶端的 Windows 平台上裝載的 WCF 服務。雖然您就必須修改特定 C# 程式碼 (通常是 C + + 或 Perl) 用戶端所支援的語言此處介紹我,整體的技巧會相同。

此外,較通訊端為主的方法是相當適合安全性測試 (您必須假設任何 WCF 服務將會受限於非友軍通訊端探查) 與效能測試 (以通訊端的方法是直接及可提供來回行程時間的比較基準資料)。

Dr。James McCaffrey  適用於 Volt 資訊科學 Inc.他負責管理軟體工程師在 Microsoft 台北市,Wash.,工作校園的技術訓練。他已投入包括 Internet Explorer] 和 [MSN 搜尋數個 Microsoft 產品。Dr.McCaffrey 是 「.NET 測試自動化食譜 」 (Apress 2006) 的作者,可以達到在 jammc@microsoft.com.

多虧給來檢閱這份文件的技術專家下列:Carlos Figueira