演练:使用自定义测试条件确认存储过程的结果

更新:2010 年 12 月

在此功能扩展演练中,将创建一个测试条件,并将通过创建数据库单元测试来确认其功能。 此过程包括创建测试条件的类库项目,以及为测试条件进行签名和注册。 如果已有要更新的测试条件,请参见如何:从以前的版本升级自定义测试条件

本演练阐释了以下任务:

  1. 如何创建测试条件。

  2. 如何用强名称为程序集签名。

  3. 如何向项目添加必要的引用。

  4. 如何生成功能扩展。

  5. 如何注册新的功能扩展。

  6. 如何测试新的功能扩展。

系统必备

必须安装 Visual Studio 高级专业版 或 Visual Studio 旗舰版 才能完成此演练。

创建自定义测试条件

首先,将创建一个类库。

创建类库

  1. 在**“文件”菜单上,单击“新建”,然后单击“项目”**。

  2. 在**“新建项目”对话框的“项目类型”下,单击“Visual C#”**。

  3. 在**“模板”下,选择“类库”**。

  4. 在**“名称”文本框中,键入 ColumnCountCondition,然后单击“确定”**。

接下来,将为项目签名。

为项目签名

  1. 在**“项目”菜单上,单击“ColumnCountCondition 属性”**。

  2. 在**“签名”选项卡上,选中“为程序集签名”**复选框。

  3. 在**“选择强名称密钥文件”框中,单击“<新建...>”**。

    将显示**“创建强名称密钥”**对话框。

  4. 在**“密钥文件名称”**框中,键入 SampleKey。

  5. 键入并确认密码,再单击**“确定”**。

    在生成解决方案时,将使用密钥文件对程序集进行签名。

  6. 在**“文件”菜单上,单击“全部保存”**。

  7. 在**“生成”菜单上,单击“生成解决方案”**。

接下来,要向项目添加必要的引用。

向项目添加适当的引用

  1. 在**“解决方案资源管理器”**中选择 ColumnCountCondition 项目。

  2. 在**“项目”菜单上,单击“添加引用”**。

    将打开**“添加引用”**对话框。

  3. 选择**“.NET”**选项卡。

  4. 在**“组件名称”**列中,找到以下组件:

    提示

    按住 Ctrl 键同时单击,以选择多个组件。

  5. 选择了所有所需的组件后,单击**“确定”**。

    此时将在**“解决方案资源管理器”中该项目的“引用”**节点下显示所选的引用。

创建 ResultSetColumnCountCondition 类

接下来,将 Class1 重命名为 ResultSetColumnCountCondition,并从 TestCondition 派生该类。 ResultSetColumnCountCondition 类是一个简单的测试条件,该条件确认结果集中返回的列数是否与您的预期相同。 您可以使用该条件来确保存储过程的协定正确无误。

创建测试条件类

  1. 在**“解决方案资源管理器”中,右击 Class1.cs,单击“重命名”**,然后键入 ResultSetColumnCountCondition.cs。

  2. 单击**“是”**确认将所有引用重命名为 Class1。

  3. 打开 ResultSetColumnCountCondition.cs 文件,并将以下 using 语句添加到文件中:

    using System;
    using System.Collections.Generic;
    using Microsoft.Data.Schema.UnitTesting;
    using Microsoft.Data.Schema.UnitTesting.Conditions;
    using Microsoft.Data.Schema.Extensibility;
    using System.ComponentModel;
    using System.Data;
    using System.Data.Common;
    using Microsoft.Data.Schema;
    
     
    namespace ColumnCountCondition
    {
        public class ResultSetColumnCountCondition
    
  4. TestCondition 派生类:

        public class ResultSetColumnCountCondition : TestCondition
    
  5. 添加 DatabaseSchemaProviderCompatibilityAttribute 特性。 有关更多信息,请参见用自定义数据生成器生成专用的测试数据

    [DatabaseSchemaProviderCompatibility(typeof(DatabaseSchemaProvider))]
       [DatabaseSchemaProviderCompatibility(null)]
        [DisplayName("ResultSet Column Count")]
        public class ResultSetColumnCountCondition : TestCondition
    

    由于测试条件具有两个兼容性特性,因此:

    • 当存在继承自 DatabaseSchemaProvider 的任何数据库架构提供程序时,将加载测试条件。 这将处理数据库单元测试设计器具有数据库架构提供程序上下文的情况。 如果希望测试条件特定于 SQL Server,则可以改为指定 SqlDatabaseSchemaProvider。

    • 当不存在任何数据库架构提供程序时,将加载测试条件。 当数据库单元测试加载不具有数据库架构提供程序的扩展时,将发生此情况。

  6. 添加 DisplayName 特性:

        [DatabaseSchemaProviderCompatibility(typeof(DatabaseSchemaProvider))]
            [DatabaseSchemaProviderCompatibility(null)]
        [DisplayName("ResultSet Column Count")]
        public class ResultSetColumnCountCondition : TestCondition
    
  7. 创建成员变量:

        {
            private int _resultSet;
            private int _count;
            private int _batch;
     
    
  8. 创建构造函数:

            public ResultSetColumnCountCondition()
            {
                _resultSet = 1;
                _count = 0;
                _batch = 1;
            }
     
    
  9. 重写 Assert 方法。 该方法包括 IDbConnection(表示与数据库的连接)和 ExecutionResult 的参数。 方法使用 DataSchemaException 处理错误。

            //method you need to override
            //to perform the condition verification
            public override void Assert(DbConnection validationConnection, ExecutionResult[] results)
            {
                //call base for parameter validation
                base.Assert(validationConnection, results);
     
                //verify batch exists
                if (results.Length < _batch)
                    throw new DataSchemaException(String.Format("Batch {0} does not exist", _batch));
     
                ExecutionResult result = results[_batch - 1];
     
                //verify resultset exists
                if (result.DataSet.Tables.Count < ResultSet)
                    throw new DataSchemaException(String.Format("ResultSet {0} does not exist", ResultSet));
     
                DataTable table = result.DataSet.Tables[ResultSet - 1];
     
                //actual condition verification
                //verify resultset column count matches expected
                if (table.Columns.Count != Count)
                    throw new DataSchemaException(String.Format(
                        "ResultSet {0}: {1} columns did not match the {2} columns expected",
                        ResultSet, table.Columns.Count, Count));
            }
     
    
  10. 添加以下方法,该方法重写 ToString 方法:

            //this method is called to provide the string shown in the
            //test conditions panel grid describing what the condition tests
            public override string ToString()
            {
                return String.Format(
                    "Condition fails if ResultSet {0} does not contain {1} columns",
                    ResultSet, Count);
            }
     
    
  11. 使用 CategoryAttributeDisplayNameAttributeDescriptionAttribute 特性添加以下测试条件属性:

            //below are the test condition properties
            //that are exposed to the user in the property browser
            #region Properties
     
            //property specifying the resultset for which
            //you want to check the column count
            [Category("Test Condition")]
            [DisplayName("ResultSet")]
            [Description("ResultSet Number")]
            public int ResultSet
            {
                get { return _resultSet; }
     
                set
                {
                    //basic validation
                    if (value < 1)
                        throw new ArgumentException("ResultSet cannot be less than 1");
     
                    _resultSet = value;
                }
            }
     
            //property specifying
            //expected column count
            [Category("Test Condition")]
            [DisplayName("Count")]
            [Description("Column Count")]
            public int Count
            {
                get { return _count; }
     
                set
                {
                    //basic validation
                    if (value < 0)
                        throw new ArgumentException("Count cannot be less than 0");
     
                    _count = value;
                }
            }
     
            #endregion
        }
    }
    

最终代码应如下所示:

using System;
using System.Collections.Generic;
using Microsoft.Data.Schema.UnitTesting;
using Microsoft.Data.Schema.UnitTesting.Conditions;
using Microsoft.Data.Schema.Extensibility;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using Microsoft.Data.Schema;

namespace ColumnCountCondition
{
DatabaseSchemaProviderCompatibility(typeof(DatabaseSchemaProvider))]
        [DatabaseSchemaProviderCompatibility(null)]

    [DisplayName("ResultSet Column Count")]
    public class ResultSetColumnCountCondition : TestCondition
    {
        private int _resultSet; 
        private int _count; 
        private int _batch; 

        public ResultSetColumnCountCondition()
        {
            _resultSet = 1; 
            _count = 0; 
            _batch = 1; 
        }

        //method you need to override
        //to perform the condition verification
        public override void Assert(DbConnection validationConnection, ExecutionResult[] results) 
        {
            //call base for parameter validation
            base.Assert(validationConnection, results); 

            //verify batch exists
            if (results.Length < _batch) 
                throw new DataException(String.Format("Batch {0} does not exist", _batch)); 

            ExecutionResult result = results[_batch - 1]; 

            //verify resultset exists
            if (result.DataSet.Tables.Count < ResultSet) 
                throw new DataException(String.Format("ResultSet {0} does not exist", ResultSet)); 

            DataTable table = result.DataSet.Tables[ResultSet - 1]; 

            //actual condition verification
            //verify resultset column count matches expected
            if (table.Columns.Count != Count) 
                throw new DataException(String.Format(
                    "ResultSet {0}: {1} columns did not match the {2} columns expected",
                    ResultSet, table.Columns.Count, Count)); 
        }
        //this method is called to provide the string shown in the
        //test conditions panel grid describing what the condition tests
        public override string ToString()
        {
            return String.Format(
                "Condition fails if ResultSet {0} does not contain {1} columns",
                ResultSet, Count); 
        }
         //below are the test condition properties
        //that are exposed to the user in the property browser
        #region Properties

        //property specifying the resultset for which
        //you want to check the column count
        [Category("Test Condition")]
        [DisplayName("ResultSet")]
        [Description("ResultSet Number")]
        public int ResultSet
        {
            get { return _resultSet; }
 
            set
            {
                //basic validation
                if (value < 1) 
                    throw new ArgumentException("ResultSet cannot be less than 1");
 
                _resultSet = value; 
            }
        }
 
        //property specifying
        //expected column count
        [Category("Test Condition")]
        [DisplayName("Count")]
        [Description("Column Count")]
        public int Count
        {
            get { return _count; }
 
            set
            {
                //basic validation
                if (value < 0) 
                    throw new ArgumentException("Count cannot be less than 0");
 
                _count = value; 
            }
        }
 
        #endregion
    }
}

接下来,将生成项目。

生成项目

  • 在**“生成”菜单上,单击“生成解决方案”**。

接下来,将收集项目中生成的程序集信息,其中包括版本、区域性和 PublicKeyToken。

收集程序集信息

  1. 在**“视图”菜单上,单击“其他窗口”,然后单击“命令窗口”打开“命令”**窗口。

  2. 在**“命令”**窗口中,键入以下代码。 将 FilePath 替换为已编译的 .dll 文件的路径和文件名。 在路径和文件名的两侧加双引号。

    提示

    默认情况下,已编译的 .dll 文件的路径是“您的解决方案路径\bin\Debug”或“您的解决方案路径\bin\Release”。

    ? System.Reflection.Assembly.LoadFrom(@"FilePath").FullName
    
  3. 按 Enter。 此时该行应类似于以下内容,其中含有您的特定 PublicKeyToken:

    "ColumnCountCondition, Version=1.0.0.0, Culture=neutral, PublicKeyToken=nnnnnnnnnnnnnnnn"
    

    记下或复制此程序集信息;下一过程中将使用这些信息。

接下来,将使用上一过程中收集的程序集信息创建 XML 文件。

创建 XML 文件

  1. 在**“解决方案资源管理器”**中选择 ColumnCountCondition 项目。

  2. 在**“项目”菜单上选择“添加新项”**。

  3. 在**“模板”窗格中,找到并选择“XML 文件”**项。

  4. 在**“名称”文本框中键入 ColumnCountCondition.Extensions.xml,然后单击“添加”**按钮。

    此时 ColumnCountCondition.Extensions.xml 文件将添加到**“解决方案资源管理器”**的项目中。

  5. 打开 ColumnCountCondition.Extensions.xml 文件,将其更新以匹配以下 XML。 替换上一过程中检索的版本、区域性和 PublicKeyToken。

    <?xml version="1.0" encoding="utf-8"?>
    <extensions assembly=""
                version="1" xmlns="urn:Microsoft.Data.Schema.Extensions"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="urn:Microsoft.Data.Schema.Extensions Microsoft.Data.Schema.Extensions.xsd">
    
      <extension type="ColumnCountCondition.ResultSetColumnCountCondition" assembly="ColumnCountCondition, Version=1.0.0.0, Culture=neutral, PublicKeyToken=nnnnnnnnnnnnnnnn" enabled="true"/>
    </extensions>
    
  6. 在**“文件”菜单上,单击“保存”**。

接下来,要将程序集信息和 XML 文件复制到 Extensions 目录。 Visual Studio 启动时将会标识 %Program Files%\Microsoft Visual Studio 10.0\VSTSDB\Extensions 目录和子目录中的任何扩展,并注册这些扩展以便在会话中使用。

将程序集信息和 XML 文件复制到 Extensions 目录

  1. 在 %Program Files%\Microsoft Visual Studio 10.0\VSTSDB\Extensions\ 目录中创建一个名为 CustomConditions 的新文件夹。

  2. 将 ColumnCountCondition.dll 程序集文件从输出目录(默认情况下为 My Documents\Visual Studio 2010\Projects\CustomConditions\CustomConditions\bin\Debug\)复制到已创建的 %Program Files%\Microsoft Visual Studio 10.0\VSTSDB\Extensions\CustomConditions 目录。

  3. 将 ColumnCountCondition.Extensions.xml 文件(默认情况下位于 My Documents\Visual Studio 2010\Projects\CustomConditions\CustomConditions\ 目录中)复制到已创建的 %Program Files%\Microsoft Visual Studio 10.0\VSTSDB\Extensions\CustomConditions 目录。

    提示

    最佳做法是将扩展程序集放在 %Program Files%\Microsoft Visual Studio 10.0\VSTSDB\Extensions 目录下的文件夹中。 这样将帮助您识别随产品包括了哪些扩展,以及哪些扩展是您自定义创建的。 建议使用文件夹将扩展按特定类别进行组织。

接下来,将启动 Visual Studio 的新会话并创建数据库项目。

启动 Visual Studio 的新会话并创建数据库项目

  1. 再启动 Visual Studio 的一个会话。

  2. 在**“文件”菜单上,单击“新建”,然后单击“项目”**。

  3. 在**“新建项目”对话框的“已安装的模板”列表中,展开“数据库”节点,然后单击“SQL Server”**。

  4. 在细节窗格中,单击**“SQL Server 2008 数据库项目”**。

  5. 在**“名称”文本框中,键入 SampleConditionDB,然后单击“确定”**。

接下来,将创建单元测试。

在新测试类中创建数据库单元测试

  1. 在**“测试”菜单上,单击“新建测试”**。

    提示

    还可以打开“解决方案资源管理器”,右击某个测试项目,指向“添加”,然后单击“新建测试”

    随即出现**“添加新测试”**对话框。

  2. 在**“模板”列表中,单击“数据库单元测试”**。

  3. 在**“测试名称”**中,键入 SampleUnitTest。

  4. 在**“添加到测试项目”中,单击“创建新的 Visual C# 测试项目”**。

  5. 单击**“确定”**。

    此时将出现**“新建测试项目”**对话框。

  6. 键入“SampleUnitTest”作为项目名称。

  7. 单击**“取消”**,在未将测试项目配置为使用数据库连接的情况下创建单元测试。

    提示

    有关用数据库连接创建和配置数据库单元测试的更多信息,请参见如何:创建空的数据库单元测试

    此时将在**“数据库单元测试设计器”**中出现一个空测试。 将向测试项目添加一个 Visual C# 源代码文件。

  8. 单击**“单击此处以创建”**完成创建单元测试。

最后,将看到新条件显示在 SQL Server 项目中。

查看新条件

  1. 在**“数据库单元测试设计器”“测试条件”下的“名称”**列下,单击 inconclusiveCondition1 测试。

  2. 单击**“删除测试条件”**工具栏按钮,删除 inconclusiveCondition1 测试。

  3. 单击**“测试条件”下拉框,并选择“ResultSet 列计数”**。

  4. 单击**“添加测试条件”**工具栏按钮,添加自定义测试条件。

  5. 在**“属性”窗口中,配置“Count”(计数)、“Enabled”(已启用)和“ResultSet”**(结果集)属性。

    有关更多信息,请参见如何:向数据库单元测试中添加条件

请参见

任务

如何:为数据库单元测试设计器创建测试条件

如何:注册和管理功能扩展

概念

创建和定义数据库单元测试

其他资源

管理程序集签名和清单签名

修订记录

日期

修订记录

原因

2010 年 12 月

已对最终代码进行少量纠正(特性)以解决客户反馈。

客户反馈