WCF 测试简介

代码下载位置: TestRun2008_07.exe (173 KB)
在线浏览代码

无论您是刚刚接触 Windows ® Communication Foundation (WCF) 还是有过一点使用经验,都可以通过一些测试技巧和原理轻松掌握 WCF。有多种方法可以弄清 WCF 究竟是什么,我更倾向于将 WCF 服务看作是 Web 服务的重要扩展。与 Web 服务一样,WCF 服务允许您使用面向服务的体系结构来创建分布式系统。但是,WCF 服务提供了更大的灵活性(如选择传输协议)和附加功能(如事务和安全性)。WCF 绝非仅仅是 Web 服务的扩展,但如果您刚刚接触 WCF,开始时这样看待 WCF 服务也未尝不可。
图 1 是一个简单但极具代表性的 WCF 方案。在这里,Internet Explorer ® 充当客户端程序并访问 ASP.NET Web 应用程序,用来接受来自用户的一些文本并计算其加密哈希值。ASP.NET Web 应用程序在后台调用 WCF 服务来实际执行哈希运算。在这个特定方案中,WCF 服务由 IIS 承载并被 ASP.NET Web 应用程序使用,但正如我要在稍后进行说明的那样,除 IIS 之外,WCF 服务还可以通过多种方式承载,并且实际上可被任何类型的应用程序或其他服务使用。
图 1 典型的 WCF 应用程序方案(单击图像可查看大图)
最基本的 WCF 服务测试类型包括验证服务操作功能的正确性。一种方法是通过应用程序 UI 手动测试 WCF 服务。尽管手动测试是必要的,但使用此方法来测试 WCF 服务的基本功能会是一项耗时、易错、低效而且乏味的工作。
更好的方法是编写测试自动化软件,一个类似于 图 2 所示的运行程序。此屏幕快照显示了我编写的一个控制台应用程序测试工具,它可以将输入文本直接提供给后端 WCF 服务,然后从该服务获取响应消息并确定测试用例结果(通过或失败)。 图 3 中的图表是一个简化视图,它总结了图 1 和图 2 中所示程序之间的关系。在许多情况下,WCF 服务都从后端数据库检索信息或者从 Web 服务或 WCF 服务检索信息,但我并未在 图 3 中包括这些情况。
图 2 测试 WCF 服务(单击图像可查看大图)
图 3 简化关系(单击图像可查看大图)
接下来,我将对后端 WCF 服务进行说明以便您对所测试的内容有准确的了解,然后还将简要讨论 图 1 中所示的使用 WCF 服务的 ASP.NET Web 应用程序,此外还会对测试工具做详细的介绍。最后我会讲一讲其他一些 WCF 测试方案。

待测试系统
待测试系统由后端 WCF 服务和使用该 WCF 服务的 ASP.NET Web 应用程序组成。WCF 服务非常灵活。创建 WCF 服务时的重要设计决策之一是如何为该服务选择承载机制。主要有四种方法:使用 IIS、使用 Windows ® Service、自承载以及使用 Windows Activation Service (WAS)。您可能很熟悉 IIS 和 Windows Service 的使用。自承载涉及在 Microsoft ® .NET Framework 托管的程序(如控制台应用程序)内承载 WCF。WAS 是 Windows Server ® 2008 和 Windows Vista ® 中提供的一种新的进程激活机制。每种 WCF 承载方案都有一些优点和缺点,具体取决于您的特定开发方案。在本专栏的 WCF 服务示例中,我决定使用 IIS。此方案能充分利用 IIS 的一些优势,例如内置集成的管理和监视、进程回收、空闲关机和基于消息的激活等功能。
创建由 IIS 承载的 WCF 服务极为简单。首先我在 Windows Server 2003 上激发 Visual Studio ® 2008。请注意,如果您决定在运行 Windows Server 2008 或 Windows Vista 的计算机上开发 WCF 服务,在开发期间必须处理与其增强的安全功能有关的一些问题。但限于篇幅,我无法在此对这些问题进行说明。
虚拟实验室:使用 LINQ 进行测试
测试 SQL 存储过程时,LINQ 可以明显简化测试自动化程序。您可以在我们的虚拟实验室中体验这些 LINQ 测试方法。包括本专栏所介绍的项目和预配置的 SQL Server ® 数据库在内,一切都已安装完毕并准备就绪。只需根据显示的内容开始实验和编码即可。

在虚拟实验室中进行试验:
接下来,我从 Visual Studio 菜单中选择“文件”|“新建”|“网站”选项。 然后从“新建网站”对话框中选择“WCF 服务”模板(在 Visual Studio 2008 中是默认安装的)并指向 .NET Framework 3.5。在“位置”字段中,选择 HTTP 并指定 localhost/WCF/CryptoHashService。此方法会在我开发计算机中的 C:\Inetpub\wwwroot\WCF\CryptoHashService 目录下创建一个完整的 Web 应用程序和 IIS 虚拟目录;但也可以在计算机的文件系统中事先选择一个位置并使用内置的 Visual Studio Web Development Server。
我决定使用 C# 作为我的实现语言;但 WCF 服务也可以使用 Visual Basic ® .NET 来实现。单击对话框中的“确定”按钮后,Visual Studio 会使用两个名为 GetData 和 GetDataUsingDataContract 的示例操作创建一个全功能的 WCF 服务。如果您看一下“解决方案资源管理器”窗口,您就会发现 Visual Studio 生成了四个密钥文件:IService.cs、Service.cs、Service.svc 和 web.config。文件 IService.cs 拥有 WCF 操作的接口定义,文件 Service.cs 拥有操作的实际实现。在本例中,我决定将这两个文件分别重命名为 ICryptoHashService.cs 和 CryptoHashService.cs。接着,我将 ICryptoHashService.cs 加载到 Visual Studio 代码编辑器中,并删除示例接口代码而将其替换为以下代码:
复制代码
[ServiceContract]
public interface ICryptoHashService
{
    [OperationContract]
    string GetCryptoHash(string s);
}
此处我只有一个单一操作 GetCryptoHash,但我也可以添加其他操作。请注意,[SeviceContract] 和 [OperationContract] 属性将在后台执行大部分实际的代码生成工作。接着,通过添加一个引用 System.Security.Cryptography 命名空间的 using 语句来编辑实现文件 CryptoHashService.cs,我编写了下列代码:
复制代码
public class CryptoHashService : ICryptoHashService
{
    public string GetCryptoHash(string s)
    {
        byte[] ba = Encoding.Unicode.GetBytes(s);
        MD5CryptoServiceProvider sp = new MD5CryptoServiceProvider();
        byte[] hash = sp.ComputeHash(ba);
        string result = BitConverter.ToString(hash);
        return result;
    }
}
首先,我更改了 CryptoHashService 类以及从中派生而来的类的名称,以匹配我在接口定义中使用的名称。在 GetCryptoHash 方法中,我只是使用 GetBytes 方法将输入参数转换为一个字节数组,然后实例化 MD5CryptoServiceProvider 类的实例,最后使用 ComputeHash 方法将我的字节数组转换为 16 子节 MD5 加密哈希值。我使用静态 BitConverter.ToString 方法将得到的哈希值从字节数组转换为能够被用户理解的字符串,然后返回该字符串。为简化示例,我省略了在生产环境中必不可少的常规错误检查,例如,检查输入参数、捕获异常等。接下来,我编辑了 Service.svc 文件以反映从 "Service" 到 "CryptoHashService" 的命名更改:
复制代码
<%@ ServiceHost Language="C#" Debug="true"   Service="CryptoHashService"
           CodeBehind=           "~/App_Code/CryptoHashService.cs" %>
通过在 web.config 中更新两个名称引用来完成名称编辑:
复制代码
<system.serviceModel>
         <services>
         <service name="CryptoHashService"     behaviorConfiguration="Servic Behavior">
    <!-- Service Endpoints -->
    <endpoint address=""binding="wsHttpBinding"         contract="ICryptoHashService">
请注意条目 binding="wsHttpBinding"。WCF 绑定是指定 WCF 服务如何与客户端进行通信的信息集合,这里所说的通信包括该服务所使用的传输协议、使用的文本编码方案等。您可以使用内置绑定,也可以创建自定义绑定。wsHttpBinding 是一个预配置的绑定,默认情况下用于创建由 IIS 承载的 WCF 服务。Visual Studio 所生成的 web.config 文件的另一部分是:
复制代码
<endpoint address="mex" binding="mexHttpBinding"
    contract="IMetadataExchange"/>
此条目指示 WCF 服务显示自身的元数据,以使客户端程序可以查看该服务以确定如何与其交互。此时,可以通过从主菜单选择“生成”|“生成解决方案”来成功生成我的 WCF 服务。也可以按快捷键 F5 来生成我的 WCF 服务并获取有关创建客户端应用程序的说明。由于我的服务是由 IIS 所承载,因此不必显式启动该服务;只要 IIS 在运行,WCF 服务即可接受传入的 WCF 消息。
现在让我们看一下 图 1 中所示的 ASP.NET Web 应用程序的创建过程。启动 Visual Studio 的一个新实例并发出“文件”|“新建”|“网站”命令。在“新建网站”对话框中,选择“ASP.NET 网站”模板并在框架目标下拉控件中选择 .NET Framework 3.5。在“位置”中选择 HTTP 并选择 C# 作为我的语言。在位置字段中键入 localhost/WCF/UtilitiesAndTools 以隐式命名我的 Web 应用程序。也可以在开发计算机中指定文件系统位置,然后使用开发 Web 服务器而不使用 IIS。接着,在 Web 应用程序中添加最简单的 UI 代码。
图 4 中的代码是基本的 UI,没有字体样式和 <hr/> 标记等格式设置细节。您可以从本专栏随附的代码下载中获取具体的 UI 代码以及本文中列出的所有代码。
复制代码
<body>
   <form id="form1" runat="server">
      <div>
      <asp:Label runat="server" ID="Label"
         Text="Demo Utilities Featuring WCF Services" />
      <asp:Label runat="server" ID="Label2"
         Text="Enter text here:" />
      <asp:TextBox runat="server" ID="TextBox1"
         Height="100px" Width="320px" />
      <asp:Button runat="server" ID="Button1"
         Text="Get MD5 Crypto-Hash" οnclick="Button1_Click"
         Width="150px" />
      <asp:Button runat="server" ID="Button2"
         Text="Get SHA1 Crypto-Hash"
         Width="150px" />
      <asp:Label runat="server" ID="Label3"
      Text="Crypto-Hash of your text (computed by WCF Service) is:" />
      <asp:TextBox runat="server" ID="TextBox2"
         Width="320px" />
      </div>
   </form>
</body> 
此时,我的 ASP.NET Web 应用程序并不了解我的 WCF 服务;但是,WCF 和 ASP.NET 技术是被设计为可以无缝协作的。在 Web 应用程序项目的“解决方案资源管理器”窗口中,右键单击项目名称,然后从上下文菜单中选择“添加服务引用”。请注意,这是一个新选项,它完善了原来的选项“添加引用”(通常用于 DLL 库和 .NET 命名空间)和“添加 Web 引用”(通常用于 ASP.NET Web 服务)。
在得到的“添加服务引用”对话框中,键入 localhost/WCF/CryptoHashService/Service.svc,然后单击“执行”按钮。“添加服务引用”工具随后将扫描指定位置寻找可用服务并显示找到的服务;在本例中是 CryptoHashService WCF 服务。在对话框的“命名空间”字段中,接受简单的、说明性不是很强的默认名称 ServiceReference1,然后单击“确定”按钮。Visual Studio 生成了应用程序连接到 WCF 服务时所需的所有代理代码。特别是我得到了一个名为 CryptoHashServiceClient 的类(即,附加到 WCF 服务名称后的 "Client"),通过它可以与 CryptoHashService 服务进行通信。
在设计视图中,双击 Button1 控件以指示 Visual Studio 注册该控件的事件处理程序。然后将以下代码添加到 Button1_Click 方法中:
复制代码
try  
{
    string s = TextBox1.Text;
    ServiceReference1.CryptoHashServiceClient c = 
       new ServiceReference1.CryptoHasahServiceClient();
    string h = c.GetCryptoHash(s);
    TextBox2.Text = h;
}
catch(Exception ex)
{
    TextBox2.Text = ex.Message;
}
简直是太简单了。我将文本提取到 TextBox1 中、实例化自动生成的 CryptoHashServiceClient 类的一个实例、调用对象的 GetCryptoHash 方法,并在 TextBox2 中显示得到的 MD5(消息摘要算法 5)加密哈希值。 图 1中 Web 应用程序的用户界面显示了一个计算 SHA-1(安全哈希算法 1)加密哈希值的按钮控件,但我并没有实现该功能来模拟开发中的系统。生成 Web 应用程序后,用户可以启动 Internet Explorer 并导航到该应用程序,然后输入一些文本,获取由后端 WCF 服务计算得出的文本 MD5 加密哈希值,如 图 1 所示。

测试工具
现在,让我们看一下 图 2 所示的简单测试工具的代码。实际上,测试工具程序只是一个 WCF 客户端,用于将输入消息发送到待测试的 WCF 服务并验证返回消息是否正确。首先启动 Visual Studio 的一个新实例并创建一个名为 TestHarness 的 C# 控制台应用程序。在 图 2 所示的示例中,可注意到我将工具的位置设置为 C:\Inetpub\wwwroot 下的一个子目录,以使工具代码靠近待测试系统。实际上可以将工具放在任何位置,包括单独的测试主机上。 图 5 显示了测试工具的整体结构。
复制代码
using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;

namespace TestHarness
{
    class Program
    {
        static void Main(string[] args)
        {
        try
            {
                 // display startup messages
                 // set up test case data collection, testCases
                 // set up WCF binding object, wsb
                 // set up WCF address object, epa

                 CryptoHashServiceClient c =
                     new CryptoHashServiceClient(wsb, epa);

                foreach (TestCaseData tcd in testCases)
                {
                     // echo case ID, input, expected values
                     // call GetCryptoHash method, fetch return
                     // compare actual return with expected
                     // print pass/fail result
                }
                Console.WriteLine("\nDone");
            }
            catch (Exception ex)
            {
                Console.WriteLine("Fatal error: " + ex.Message);
            }
        }
    }

    class TestCaseData
    {
        public readonly string caseID;
        public readonly string input;
        public readonly string expected;
        public TestCaseData(string caseID, string input, string expected)
        {
            this.caseID = caseID; this.input = input; this.expected =
              expected;
        }
    }
}
首先添加一个指向 System.ServiceModel 命名空间的 using 语句,对我的测试工具进行编码。此命名空间包含核心 WCF 服务功能。接着设置测试用例数据。在 图 5 中,您可以看到我创建了一个简单的 TestCaseData 类来保存测试用例 ID、输入内容和预期值。在生产环境中,您还可以添加其他字段(包括 WCF 服务绑定信息),稍后我会进行解释。现在,通过创建一个通用的 List 对象并用 TestCaseData 对象对其进行填充,来将测试用例数据直接嵌入到我的工具中:
复制代码
List<TestCaseData> testCases = new List<TestCaseData>();
testCases.Add(new TestCaseData("001", "Hello world",
    "E6-76-0D-55-5C-32-F6-6F-5E-15-93-31-DB-20-FD-8E"));
testCases.Add(new TestCaseData("002", "Goodbye world",
    "1A-05-3C-C0-4A-18-13-06-0E-AC-EA-BA-46-EC-CF-B1"));
testCases.Add(new TestCaseData("003", "",
    "D4-1D-8C-D9-8F-00-B2-04-E9-80-09-98-EC-F8-42-7E"));
测试用例数据也可以在外部存储(如 XML 文件或 SQL 表)中设置。此处我使用了三个测试用例,但在实际中可以使用数千个。在软件测试过程中,最困难的环节是如何鉴别良好的测试用例输入(彻底测试待测试系统)并确定预期结果。
现在,尽管您可以从头编写 WCF 客户端代码,但如果使用 Visual Studio 2008 随附提供的 svcutil.exe 命令行工具来生成代理代码和 WCF 配置文件则会简单很多。在本例中,我启动了一个 Visual Studio 命令外壳(它知道 svcutil.exe 的位置),然后输入以下命令:
复制代码
> svcutil.exe http://localhost/WCF/CryptoHashService/Service.svc
在 WCF 服务的位置运行且没有任何附加参数的 Svcutil.exe 会从该服务读取 WCF 元数据并为我生成两个文件。第一个文件是 CryptoHashService.cs(目标 WCF 服务的名称,后跟 .cs 扩展名),它包含 C# 代理代码,可以使用此代码与我的 WCF 服务进行消息传递。第二个文件是 output.config,它包含目标 WCF 服务使用的 WCF 绑定信息(传输协议、超时设置、文本编码等)。这两个文件生成完毕后,右键单击测试工具项目并将 CryptoHashService.cs 文件添加到项目中。也可以直接将此代码复制或粘贴到我的测试工具中。
现在有两种方法可以使用 output.config 文件中的绑定信息。一种方法是将文件重命名为 app.config,然后将其添加到客户端项目中。第二种方法是检查 output.config 文件中的数据,然后编写代码以编程方式将 output.config 中所示的值分配给绑定对象。编写常规 WCF 客户端程序时,app.config 方法通常是比编程方法更好的选择。由于 app.config 文件是普通文本文件,由客户端程序在运行时读取,因此如果关联的 WCF 服务的绑定信息发生变化,则只需更改 app.config 文件便可更改相应的客户端绑定信息,而无需重新编译客户端。但是,在 WCF 测试工具客户端的特殊情况下,有时最好以编程方式指定绑定信息。使用编程方法您可以轻松地在测试用例的输入过程中传递绑定信息。此处我使用编程方法。我将实例化一个 WSHttpBinding 对象。
复制代码
WSHttpBinding wsb = new WSHttpBinding();
现在我可以将值分配给绑定对象的 Name 属性和各种时间属性:
复制代码
wsb.Name = "WSHttpBinding_ICryptoHashService";
wsb.CloseTimeout = TimeSpan.Parse("00:01:00");
wsb.OpenTimeout = TimeSpan.Parse("00:01:00");
wsb.ReceiveTimeout = TimeSpan.Parse("00:10:00");
wsb.SendTimeout = TimeSpan.Parse("00:01:00");
我通过以可视化方式检查 output.config 文件(由 svcutil.exe 工具生成)中绑定条目的属性来确定这些值。在本例中,我将使用在创建 WCF 服务时 Visual Studio 所生成的所有默认值。其余的绑定属性也以类似的方式来指定值:
复制代码
wsb.BypassProxyOnLocal = false;
wsb.TransactionFlow = false;
wsb.HostNameComparisonMode =
    System.ServiceModel.HostNameComparisonMode.StrongWildcard;
wsb.MaxBufferPoolSize = 524288;
wsb.MaxReceivedMessageSize = 65536;
wsb.MessageEncoding =
    System.ServiceModel.WSMessageEncoding.Text;
wsb.TextEncoding = System.Text.Encoding.UTF8;
wsb.UseDefaultWebProxy = true;
wsb.AllowCookies = false;
现在设置我的代理对象:
复制代码
string uri =
    "http://vte014.vte.local/WCF/CryptoHashService/Service.svc";
EndpointAddress epa = new EndpointAddress(uri);
CryptoHashServiceClient c =
    new CryptoHashServiceClient(wsb, epa);
CryptoHashServiceClient 类在 CryptoHashService.cs 文件的内部定义,此文件是使用我创建的 svcutil.exe 自动生成的。该类构造函数接受绑定对象(我刚刚以编程方式设置的)和指向 WCF 服务的 EndPointAddress 对象。现在我的客户端已经被实例化,接下来我可以开始迭代每个测试用例并执行待测试 WCF 服务。
图 6 中,对于每个测试用例,我只是向控制台发送一条通过/失败消息。在生产环境中,您可能需要执行更多操作,例如跟踪通过的用例总数和失败的用例数、以编程方式发送电子邮件消息(如果一个或多个测试用例失败)、将结果保存到外部数据存储设备等。如果您使用 Team Foundation Server,则可以通过我在“使用 Team System 自定义测试自动化”中介绍的方法来管理此测试工具,该文章发表在 2008 年的“测试运行”专栏中(请参阅 msdn.microsoft.com/magazine/cc164248)。
复制代码
foreach (TestCaseData tcd in testCases)
{
    Console.WriteLine("Case ID  = " + tcd.caseID);
    Console.WriteLine("Input    = " + tcd.input);
    Console.WriteLine("Expected = " + tcd.expected);

    string actual = c.GetCryptoHash(tcd.input);
    Console.WriteLine("Actual   = " + actual);
    if (actual == tcd.expected)
        Console.WriteLine("* Pass *");
    else
        Console.WriteLine("** FAIL **");
}

其他注意事项
本月我所提出的一些方法可以为初步了解基本的 WCF 服务测试奠定坚实的基础。但是有关 WCF 测试还有许多其他方面的内容,我将在以后的专栏中加以介绍。其中的大多数附加测试主题是通过 WCF 强大的灵活性来实现的。例如,WCF 不但允许系统使用传输级别(例如,使用 HTTPS)的安全性,也允许使用较低级别的安全性。尽管 WCF 服务可以使用 HTTP,但 WCF 也允许系统使用多种其他机制(包括 TCP 和命名管道)进行通信。正如我在上面介绍的,WCF 服务可以在 IIS 中承载,但 WCF 服务也可以通过其他方式承载(包括通过 Windows 服务和自承载托管的应用程序)。WCF 服务可以支持多个端点,每个端点都有一个不同的地址、绑定和约定。WCF 支持请求答复式消息传送和双工式消息传送模式。所有这些 WCF 方案以及许多其他方案在进行全面测试时都有一些值得关注的暗示。
本专栏中介绍的基本 WCF 功能测试方案只代表全面 WCF 测试的一部分。由于我的虚拟 WCF 加密哈希服务非常简单,因此整个逻辑都包含在单个的 GetCryptoHash 方法中。在一些实际的方案中,您可能需要编写封装业务逻辑的代码和单独的封装服务功能的代码。此方法允许您分别测试业务逻辑和服务,从而简化您的测试工作。
使用 Visual Studio Team System 创建 WCF 服务时,您可以利用内置的单元测试支持(如果您使用的是测试驱动的开发原理)。您也可以使用 Visual Studio 2008 随附的 WcfTestClient.exe 测试客户端实用程序来执行 WCF 服务的手动测试,以实现我在本专栏中提供的自动测试类型(请参见《MSDN ® 杂志》我的同事 Juval Lowy 撰写的专栏,网址为 msdn.microsoft.com/magazine/cc163289)。除了纯粹的功能测试以外,您还可以使用 Visual Studio 中集成的负载测试工具来执行负载测试。
请将您想向 James 询问的问题和提出的意见发送至 testrun@microsoft.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值