65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 SQL Server Data Tools (SSDT) 进行 SQL 单元测试

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.64/5 (5投票s)

2018年2月8日

CPOL

9分钟阅读

viewsIcon

33296

downloadIcon

426

使用 SQL Server 数据工具 (SSDT) 进行 SQL 单元测试

本文包含什么?

本文解释了如何使用 SQL 单元测试功能来使应用程序更加健壮。虽然我们可以使用 Microsoft 提供的示例 AdventureWorks 数据库,但它对本文来说太大了,我们将创建一个非常简单的数据库以避免混淆并涵盖所有主题。数据库脚本在需要的地方提供,只需复制并在你的 SQL Server 版本中执行。

本文不包含什么?

它不包含 Visual Studio 2015 或更早版本的实现步骤,尽管相同的步骤可能适用于 VS 2015 或更早版本。

什么是 SQL 单元测试?

SQL 单元测试是指对数据库的数据、架构、存储过程、函数、视图和触发器进行独立的单元测试。就像通过 NUnit 或 Visual Studio 测试用例的代码单元测试、通过 Coded UI 进行的 UI 测试一样,SQL 测试在使应用程序健壮且无错误方面也起着重要作用。

SQL 单元测试现在已在 VS 2015 和 VS 2017 的社区版中提供,这是使用它的另一个原因。以前,此功能仅在付费版 VS 中提供。自 VS 2010 professional + 版本发布以来一直可用。

软件要求

Visual Studio Community 2017、SQL Server 2012 和 SQL Server Data Tools (SSDT)。SSDT 是一个免费工具,无需提供任何登录凭据即可下载。

请注意,应安装与 Visual Studio 版本对应的 SSDT,即,如果你使用的是 VS 2015,请安装适用于 VS 2015 的 SSDT 版本。如果你使用的是 VS 2013,请安装支持 VS 2013 的 SSDT。已安装的旧版本 SSDT 将无法与新版本 Visual Studio 一起使用。

建议使用 SQL Server 2012+ 和 VS 2012+。

2. 创建数据库并添加表

创建一个名为 "DBUnitTesting" 的数据库。然后,执行附加的脚本。如果你想使用不同的数据库名称,请修改脚本并将 "DBUnitTesting" 替换为新名称。

以下是表的结构和关系的数据库图。创建了三个表:CompanyDepartmentSubDepartment。在此,CompanyIdDepartment 表中用作外键引用,DepartmentIdSubDepartment 表中用作外键引用。SubDepartmentLog 表用于审计目的。审计表不应包含任何外键链接。

创建表脚本

使用附加的 "Scripts" zip 文件夹中的 "CreateTables.txt"。

3. 在 Visual Studio 2017 中创建项目

转到 文件-> 新建-> 项目-> SQL Server-> SQL Server 数据库项目。如果系统中正确安装了相应的 SSDT,则会显示此选项。输入任何名称,例如 "SQLUnitTestingDB"。

右键单击并选择 "导入" -> 数据库。提供有效的凭据并单击 "开始"。

几秒钟后,架构将导入到代码中。单击 "完成"。

添加新项目 -> 类 (.NET Framework),将其命名为 "TestCases"。添加以下引用

  1. 添加对之前创建的 "SQLUnitTestingDB" 项目的引用,因为它包含架构详细信息。
  2. 添加 Nuget 包 - Microsoft.VisualStudio.QualityTools.UnitTestFramework.Updated

右键单击,添加新项,选择 SQL Server,然后选择 "SQL Server 单元测试"。由于我们将首先测试 Company 表,因此将其命名为 "CompanyUnitTest"。

为什么我们创建了一个单独的类?

我们也可以在 "SQLUnitTestingDB" 项目中添加 SQL Server 单元测试,但将单元测试用例与包含架构信息的项目分开是一个好习惯。这有助于在长期内更好地维护项目,因为添加了许多测试用例。

3. 创建第一个单元测试

转到 "CompanyUnitTest.cs" 并重命名

  1. "SqlTest1" 为 "RowCountCompany"
  2. "SqlTest1Data" 为 "RowCountCompanyData"

正确的命名有助于更好地维护项目。 "RowCountCompany" 将在测试资源管理器中显示。

双击 "CompanyUnitTest.cs",设计器将打开。设计器中显示三个选项:预测试、测试、后测试。

预测试:通常用于,但不限于,在实际测试执行之前设置某些必需的条件。

测试: 主要命令或操作。

后测试: 通常用于,但不限于,如果在执行操作后需要清理表数据。

并非必须使用所有三个选项。现在,我们将使用测试选项。双击 "CompanyUnitTest",设计器将打开。在左上方,可以看到已修改的测试用例名称 "RowCountCompany"。

现在,请考虑,根据业务规则,数据库应有四个公司。请注意,单元测试不应根据数据库中存在的实际数据编写,而应根据业务需求规范文档中指定的业务规则编写。这一点非常非常重要,否则将无法实现编写单元测试用例的目标。我们的目标是将业务需求文档与数据库中存在的实际数据进行比较,并衡量偏差。这是开发人员在首次开始编写单元测试用例时常犯的错误,所以要避免。

单击 "click here to create" 链接并添加 SQL 查询。删除 "Data Checksum" 条件,然后使用 "+" 符号添加标量值。添加后,属性框将打开,在 "Expected Value" 列中输入 4。

保存并从 测试->窗口->测试资源管理器 打开测试资源管理器。右键单击并单击 "运行选定测试"。由于数据库中的数据正确,它将通过。

现在,假设数据库中的数据不正确。数据库中添加了更多公司,但业务需求规范文档中未指定。

再次在测试资源管理器中运行测试。它将失败并说明原因。这样我们就知道我们的数据不正确,必须修复。

4. 单元测试选项

SQL 单元测试提供多个选项,例如

  1. 数据校验和:这确保表中的数据未更改。

    在属性选项卡中单击 "Press to configure"。单击 "Select Connection" 并选择表。单击 "Retrieve",数据将显示。单击 "OK"。

    在测试资源管理器中运行测试用例。它将通过。在开发过程中,假设 "Toboc" 在第 4 行被错误地修改为 "Tobo"。再次运行测试,它将失败。因此,数据校验和确保数据完整性。将 "Tobo" 改回 "Toboc",测试将再次通过。

  2. 预期架构:这检查架构,而不是像 "Data checksum" 那样检查数据。即使数据被修改但架构完好无损,此测试用例也将通过。

    选择 "Press to configure" 选项,然后单击 "Select Connection",选择表。单击 "Retrieve",数据将显示。单击 "OK"。

    为了演示这一点,再次将 "Toboc" 更新为 "Tobo" 并运行所有用例。我们可以看到 "CompanyExpectedSchemaTest" 通过了,而 "CompanyDataChecksumTest" 失败了。

    在 company 表中添加新列,从而修改架构。

    再次运行测试,它将失败。此选项确保架构得到维护。

  3. 行数:在属性中将 "RowCount" 设置为 4。运行测试。

  4. 执行时间:用于检查查询或存储过程的性能(稍后在文档中讨论)。选择 "Execution time" 作为选项,并保持 00:00:00.0010000。我们可以看到错误,因为执行时间超过了预期。

  5. 空结果集:用于验证是否从数据库接收到空结果集。如果返回的行数大于 0,则测试失败。

  6. 非空结果集:用于验证是否从数据库接收到空结果集。如果未返回任何行,则测试失败。例如,在存储过程或查询出错的情况下。

    "Empty Result Set" 和 "Not Empty Result Set" 都在以不同的方式验证结果集。在这两种情况下,"ResultSet" 属性都是只读的,无法修改。

  7. 不确定:这是默认的测试条件,每当添加新测试用例时。包含此测试条件是为了表明尚未实现测试验证。在添加其他测试条件后,请从测试中删除此测试条件。

5. 理解代码后端的原理

现在,我们已经对 SQL 单元测试机制提供的选项数量有了很好的了解,我们将看看它在代码后端,即类中的工作原理。

SQL 设计器使我们能够轻松地编写和可视化测试用例,但在类中,它的行为与代码单元测试用例相同。参考 "CompanyRowCount" SQL 单元测试用例。它有两个文件:resxcsResx 文件包含查询详细信息,而 cs 类包含预期输出。

Resx 文件

Cs 文件

调试测试用例

将预期的总行数条件修改为 3。从测试资源管理器中选择一个测试用例。右键单击并选择 "Debug Selected Tests"。由于条件不匹配,将抛出带有详细信息的错误。此行为与代码单元测试中的 Assert 相同。

禁用测试用例

如果我们设置 Enabled: False,测试用例在执行期间将不会被测试,并显示为已通过。当测试用例已编写但相应功能的工作尚未完成时,可以使用此选项。稍后,随着项目的进展,我们可以启用并执行所有测试用例。

6. 验证存储过程、函数、视图和触发器

存储过程

在 SQL Server 中创建一个存储过程,该过程将向 department 表插入新行。

存储过程脚本

使用附加的 "Scripts" zip 文件夹中的 "StoredProcedure.txt"。

添加新测试用例 "DepartmentAdd"。

  1. 选择 "预测试",计算 department 表中的记录数,并将预期值设置为 6

  2. 选择 "测试",并使用存储过程将数据插入 Department 表。

  3. 选择 "后测试"。再次验证计数,然后删除数据。通常,后测试用于清理用于测试的数据。如果我们不删除插入的行,下一次测试用例将失败,因为行数是 7,而预测试说行数应该是 6

因此,在测试存储过程等时,我们应该清理插入的临时数据并为下一次做好准备,这一点很重要。我们验证存储过程的目的已经达到。

函数:创建一个函数 "GetSearchTermCount"。该函数根据搜索词返回记录数(执行 like 操作)。

函数脚本

使用附加的 "Scripts" zip 文件夹中的 "Function.txt"。

创建一个新测试用例并执行函数。由于 "Software Development" 和 "Management" 包含 "ent",因此获取了 2 条记录。

视图

创建一个视图 "FetchDetails"。

视图脚本

使用附加的 "Scripts" zip 文件夹中的 "View.txt"。

创建一个新测试用例并执行视图。将行数验证为 '9'。

触发器

创建一个触发器,在更新 "SubDepartment" 表时更新 "SubDepartmentLog" 表。

触发器脚本

使用附加的 "Scripts" zip 文件夹中的 "Trigger.txt"。

创建一个新测试用例并更新 department 表。计算 "SubDepartmentLog" 表中的行数。由于在更新 "SubDepartment" 中的记录后触发器执行了一次,因此插入了一个新值。因此,返回的行数为 1

© . All rights reserved.