UML软件工程组织

 

 

对 Information Bridge Framework 智能标记进行单元测试
 

2008-01-31 出处:快速测试

 

简介

随着 Microsoft Office Information Bridge Framework 1.0 的推广,Microsoft Office 2003 开发人员的工具箱中现在有了很多非常棒的新工具。公开 Microsoft Office Professional 2003 中的 Information Bridge Framework 功能的主要方法是智能标记;但是,为智能标记创建自动单元测试可能是一个很麻烦的过程。本文将讨论托管智能标记开发人员服务库 (MSTDSL) 的用法,它位于可从 Microsoft 下载中心得到的 Microsoft Office 2003 Smart Tag Developer Tools 工具包中,并且可以减小为基于 Information Bridge Framework 的智能标记实现自动单元测试所需的工作量。

对于像使用 Information Bridge Framework 创建的解决方案一样概略的解决方案的生存期中的所有元素进行完整的、自动的单元测试,是一个非常广泛的主题,因而无法在本文范围内进行详尽的阐述。本文只是重点讨论如何测试解决方案的智能标记部分,但是它当然不认为应该使单元测试终止于这一地步。本文也不讨论如何实现智能标记。本文使用作为 Microsoft Office Information Bridge Framework Resource Kit 1.0 下载的一部分提供的示例解决方案作为测试主体。此外,本文进行了下列假设:

  • 您熟悉使用托管代码开发智能标记。
  • 您知道如何使用 NUnit 来自动执行单元测试。
  • 您已经安装了 Information Bridge Framework 以及关联的示例客户关系管理解决方案。

为什么使用自动单元测试?

尽管没有一种工具或技术能够保证从给定的代码片段中消除所有缺陷,但单元测试是您在代码中工作时可以使用的少数几种技术之一。通过单元测试,可以在开发期间以及以后的维护期间捕捉到缺陷。一些估计显示,开发期间的单元测试有可能从给定的代码部分中消除 15% 到 55% 的缺陷 (Software Quality:Analysis and Guidelines for Success, Capers Jones, International Thomson Computer Press, 1997)。尽管这是对单元测试的价值的强有力的证明,但我们的看法是,只有在最初的开发之后,单元测试 — 更具体地说应该是自动单元测试(当用每个更改或生成运行测试时)— 才会真正体现出它的价值。自动测试提供了附加保护,以帮助确保更改不会意外改变现有的功能。

在 Information Bridge Framework 开发的上下文中,需要考虑几件事情。首先,“转椅”信息工作者所完成的工作的特点是需求不断演化 — 有时会非常快速。这些新的需求可能由新的工作要求引起,由对基础信息资源的更改引起,或者只是由了解到更多有关这些人完成工作的方式的信息而引起。但是,重要的是来自这些开发项目的信息可能用来进行业务关键的决策(它可能仅仅基于通过该开发公开的信息)。如果功能不是对于开发的每个迭代都可靠,则发生灾难性后果的可能性是巨大的。既然快速而准确地调整 Information Bridge Framework 解决方案以适应不断更改的需求是如此重要,那么不难看出自动单元测试对于这些开发项目的每个部分是何等关键。就像任何工具一样,自动单元测试不应当成为您唯一的测试项目。

使用 MSTDSL

MSTDSL 用于简化对智能标记的某些最常见功能以及对某些系统级别智能标记设置的访问。MSTDSL 的能力涵盖了非常广泛的功能。为了更加明了,本文只讨论针对指定的解决方案实现单元测试所需的方法。该讨论主要集中于构成 MSTDSL 的命名空间中的两个命名空间:识别器和操作。来自这些命名空间的实例支持对已安装的智能标记进行枚举、检索特定的智能标记实例、检查属性,并且在某些情况下,支持调用智能标记接口上的方法并且无须将它们加载到 Microsoft Office 2003 中。

该库提供了用于访问识别器和操作的类似方法。首先,分别实例化命名空间集合 RecognizerCollection 和 ActionCollection,然后调用各自的加载方法(LoadRecognizers 或 LoadActions)。通过使用上述任一方法,该调用在系统注册表中查找已安装的智能标记,并且试图实例化它找到的任何智能标记。在检索了您感兴趣的智能标记对象的实例之后,MSTDSL 为很多公开的方法提供了简化接口。应当说明的是,MSTDSL 并未公开智能标记的每个属性或方法,但是它的确提供了使用最常见属性或方法的能力。

使用 NUnit

NUnit 是一个自动单元测试框架,完全使用 C# 编写(可以使用任何 Microsoft .NET 语言编写)。您通过在由 NUnit 框架中的属性描述的对象上实现方法来创建测试。在已经实现 NUnit 之后,NUnit .exe 文件(包括命令行和图形用户界面 [GUI] 文件)可以发现这些方法,并且以自动方式运行它们。该框架极其灵活,并且使测试可以查询各种条件以及查找预期的异常。NUnit 下载随附了一个示例项目,该项目演示了测试方法的各种使用方式,包括声明各种条件和测试预期的异常。

图 1. NUnit 测试应用程序示例

NUnit 用于运行自动测试的测试应用程序

当您使用 NUnit 时,对各种条件的测试通过 NUnit.Framework.Assert 对象的多个静态方法进行了简化。NUnit 框架下载提供了有关该主题的文档,但是该演示中的大多数测试都使用 Assert.IsTrue 方法来测试 True 条件,并且使用 Assert.AreEqual 方法来查找预期的条件。如果在这两种情况下条件都失败了,则整个测试失败,并且 NUnit 应用程序会显示适当的信息。

我们之所以选择 NUnit,是因为它已经由很多开发人员使用,它具有良好的说明,它被认为很稳定,并且最好的一点在于它是免费的!尽管如此,如果您使用的是除 NUnit 以外的测试框架,那么请不要担心。只要您的测试环境支持 Microsoft .NET 框架,您就能够使我们这里描述的技术适应您自己的测试环境。

检索智能标记识别器

要测试智能标记,首先需要获得智能标记识别器的一个实例。清单 1 显示了用来从 Information Bridge Framework 示例解决方案中获得识别器的代码。首先,实例化 RecognizerCollection,并且调用它的 LoadRecognizers 方法。LoadRecognizers 调用找到已安装的识别器,并且试图实例化它们。默认行为是 MSTDSL 告诉智能标记它是 Microsoft Office Word 2003 的一个实例(通过将值 Word.Application.11 传递给该标记的 AppName 属性)。如果您希望测试使用不同的值,则可以在调用 LoadRecognizers 之前直接在集合上设置 AppName 属性。在加载它之后,在找到的所有识别器中进行迭代,并且查看名称属性以查找具有预期名称的属性。如果您的目的是测试操作智能标记,则用于获得实例的步骤是相同的,不同之处在于由 ActionCollection 对象的 LoadActions 方法加载所需的操作。

此外,智能标记 API 接口的版本 2 对于操作和识别器都有一个 SmartTagInitialize 方法。ActionCollection 对象和 RecognizerCollection 对象之间的一个区别是:ActionCollection 对象在它实现的 ISmartTagAction2 接口中加载操作时,调用该 SmartTagInitialize 方法。

清单 1. 从示例解决方案中检索识别器

RecognizerCollection recognizers =
         new RecognizerCollection();
recognizers.LoadRecognizers();
foreach(Recognizer rec in recognizers)
{
   if(rec.Name == "IBF Sample")
   {
      return rec;
   }
}
return null;

检查必需的接口

通过使用示例解决方案识别器的实例,还可以检查并确保识别器实现了必需的接口。智能标记软件开发工具包 (SDK) 文档声明,智能标记识别器起码必须实现 ISmartTagRecognizer,而操作必须实现 ISmartTagAction。要测试接口的智能标记,只需调用 MSTDSL 操作或识别器实例上的 ImplementsInterface 方法,如清单 2 所示。现在对这一点进行测试似乎不切实际,因为您可能刚刚编写了代码并且知道您完成了该实现,但是您没有办法知道某个将来的开发人员可能何时意外移除该实现。对于该示例解决方案,操作和识别器还都实现了版本 2 接口(ISmartTagRecognizer2 和 ISmartTagAction2),因此对它们进行的测试也包括在内。

清单 2. 测试必需的接口

Recognizer IBFRecognizer = GetIBFSampleRecognizer();
Assert.IsTrue(
   IBFRecognizer.ImplementsInterface("ISmartTagRecognizer"));
Assert.IsTrue(
   IBFRecognizer.ImplementsInterface("ISmartTagRecognizer2"));

测试智能标记的属性

智能标记必须实现一些属性,才能在 Microsoft Office 2003 中正常工作。根据属性的不同,在返回这些值时发生的错误(尤其是空值)可能产生不可预知的并且难以调试的结果。出于该原因,用于确保来自这些属性的值提供预期结果的测试是有用的(清单 3)。可以使用相同的过程来测试操作智能标记中的属性,本文随附的下载中包含了这方面的一个示例。

清单 3. 测试属性

Recognizer IBFRecognizer = GetIBFSampleRecognizer();
        
Assert.AreEqual("IBF Sample", IBFRecognizer.Name);
Assert.AreEqual("Microsoft.Solutions.SampleSolution.SmartTagRecognizer",
            IBFRecognizer.ProgID);
Assert.AreEqual("Smart tag used to provide context in the "
      + "Information Bridge CRM Sample", IBFRecognizer.Description);

针对识别器测试术语

识别器的主要用途是为 Microsoft Office 2003 提供相应的能力,以便分析文本中是否存在特定于解决方案的术语,并且在找到这些术语时公开调用特定于解决方案的操作的能力。要测试该功能,需要运用识别方法。示例解决方案实现了 ISmartTagRecognizer2,并且它使用 Recognize2 方法进行识别。

Recognize2 方法使识别器能够接收预分析的文本,并且还使识别器能够利用各种语言的 Microsoft Office 2003 的某些功能。在 Microsoft Office 2003 外部调用 Recognize2 可能需要完成附加的工作,但是 MSTDSL 提供了一个简化的接口,使您能够用与调用 Recognize 方法相同的方式调用 Recognize2,如清单 4 所示。在内部,MSTDSL 试图分析单词边界,并且将已分析的文本与其他参数一起传递给识别器。当然,如果识别器不能区分它所识别的内容,则它几乎没有任何价值。因此,实现了相应的测试,以确保识别器不会识别它不应当识别的文本(清单 5),如代码下载中所示。

清单 4. 测试识别器上的已知术语

string baseSentence = "I am contacting you from '{0}'"
   + "and would like to get more information.";
string[] termsToRecognize = { "Woodgrove Bank",
            "A. Datum Corporation",
            "Lucerne Publishing",
            "Contoso, Ltd." };
Recognizer ibfRecognizer = GetIBFSampleRecognizer();
foreach(string simpleTerm in termsToRecognize)
{
   string testSentence = string.Format(baseSentence,
                  simpleTerm);
   RecognizerResponses responses = ibfRecognizer.Recognize2(testSentence,
                     IF_TYPE.IF_TYPE_PARA);
   Assert.AreEqual(1, responses.Count);
   Assert.AreEqual(responses[0].TagName,
   "http://schemas.microsoft.com/InformationBridge/2004#reference"); }

清单 5. 测试未识别的文本

Recognizer ibfRecognizer = GetIBFSampleRecognizer();
string testSentence = "This is a simple sentence, that "
            + "should have no recognition involved.";
RecognizerResponses responses = ibfRecognizer.Recognize2(testSentence,
                  IF_TYPE.IF_TYPE_PARA);
Assert.AreEqual(0, responses.Count);

测试操作上的谓词

操作根据通过对 InvokeVerb 和 InvokeVerb2 的调用而调用的谓词来实现它的功能。对于 Information Bridge Framework 示例解决方案而言,操作是通过使用特定于 Information Bridge Framework 但没有在这些测试的范围内重新创建的上下文实现的;因此,对调用特定谓词的结果进行的测试未包含在内。但是,有一个用于确保操作公开了预期谓词的测试。清单 6 中显示的测试首先获得对示例解决方案操作的引用。您知道对象只公开了一个谓词,并且该谓词是用 ID 101 公开的,因此测试首先确保智能标记只公开了一个谓词。然后,测试接着基于预期的 ID 101 来检查该谓词的名称和标题。

清单 6. 测试操作上的谓词

Action ibfAction = GetIBFSampleAction();
Assert.AreEqual(1,
   ibfAction.VerbCount(
   @"http://schemas.microsoft.com/InformationBridge/2004#reference"));
Assert.AreEqual("Show Account Information", 
            ibfAction.VerbCaptionFromID(101));
Assert.AreEqual("ShowAccount",
            ibfAction.VerbNameFromID(101));

小结

单元测试是开发人员的工具箱中的一种必备的工具,而 Information Bridge Framework 开发的特性使该工具变得更加关键。针对 Information Bridge Framework 进行开发的重要保证之一,是只需使用很少的代码就可以向用户公开大量的功能。使用 MSTDSL 进行自动单元测试与针对 Information Bridge Framework 进行开发非常适合,因为它使您能够用很少的代码实现单元测试。

MSTDSL 以源代码下载的形式在它自己的 GotDotNet 工作区中提供,这使您可以修改 MSTDSL 引擎以满足自己的需要。鼓励每个人分解、增强、批评并最终改善该库和关联的实用工具。

 

组织简介 | 联系我们 |   Copyright 2002 ®  UML软件工程组织 京ICP备10020922号

京公海网安备110108001071号