Visual Studio 2010:测试驱动的开发

概述

测试驱动开发 (Test Driven Development, TDD),通常也称作测试驱动设计,是一种开发方法。在该方法中,开发人员首先编写单元测试,然后编写实际系统代码来确保可以顺利通过单元测试。可以将单元测试看作是系统行为的小型规范;首先编写单元测试可以让开发人员仅编写足够通过测试的代码,有助于确保系统的紧凑、轻量,并能明确专注于满足已确定的需求。 

TDD 的步调是“红色、绿色和重构。”红色表示失败测试的可视显示——最初编写的测试并不会通过,因为您还没有为它编写任何代码。绿色表示在系统中编写足够的代码以确保单元测试能顺利通过——测试运行器的用户界面现在将使用绿色图标表示测试顺利通过。重构表示对代码执行重构来提高它的紧凑性、简洁性和灵活性。在 TDD 开发人员的工作中,此周期将不断重复。

注意:本实验的目的并不是指导您如何使用 TDD;而是重点展示 Visual Studio 2010 对 TDD 的支持。如果您对 TDD 方法及其优势感兴趣,建议首先阅读以下图书,以之作为起点:

Test Driven Development in Microsoft .NET  作者:James Newkirk 和 Alexei Voronstov,ISBN 0735619484

Pragmatic Unit Testing in C# with NUnit, 2nd Edition 作者:Andy Hunt、Dave Thomas 和 Matt Hargett,ISBN 0977616673

TDD 的关键是开发人员的步调。要实现高效的开发节奏,开发人员需要拥有正确的思想,同时还要借助正确的工具来尽量提高工作速度和减少冲突。

Visual Studio 2010 引入了一些增强功能,有助于减少开发阻碍并支持开发人员专注于以下任务:编写高质量的代码。在接下来的练习中,我们将重点展示一些新特性,它们可以帮助开发人员改善其开发步调。VS10 可以帮助开发人员减少常用任务的敲键数量,加速解决方案导航,同时使用测试框架来代替 MSTest。

为了演示其新特性,我们将采用“测试优先”的方式实现一个栈,展示如何利用测试来驱动 SimpleStack 类的设计和实现。

注意:在计算机科学领域,栈是一种抽象的数据类型和数据结构,采用后进先出 (LIFO) 的原则。

如果您不熟悉栈这个数据结构概念,或者想回顾一些相关知识,请阅读更加全面的 Wikipedia 文章,更加深入地了解此概念。

目标

在本次动手实验中,您将学习如何:

•              使用新的智能标记操作来减少击键次数,让 IDE 自动生成小型的代码片段。

•              使用 Quick Search 迅速导航代码库。

               

系统要求

您必须拥有以下内容才能完成本实验:

•             Microsoft Visual Studio 2010 Beta 2

•             .Net Framework 4.0

               

安装

使用 Configuration Wizard 验证本实验的所有先决条件。要确保正确配置所有内容,请按照以下步骤进行。

注意:要执行安装步骤,您需要使用管理员权限在命令行窗口中运行脚本。

1.            如果之前没有执行,运行 Training Kit 的 Configuration Wizard。为此,运行 %TrainingKitInstallationFolder%\Labs\TestDrivenDevelopment\Setup 文件夹中的 CheckDependencies.cmd 脚本。安装先决条件中没有安装的软件(如有必要请重新扫描),并完成向导。

注意:为了方便,本实验管理的许多代码都可用于 Visual Studio 代码片段。CheckDependencies.cmd 文件启动 Visual Studio 安装程序文件安装该代码片段。

               

练习

本次动手实验由以下练习组成:

1.            为您的设计添加测试动力,即编写测试并让它们从红色(失败)变为绿色(通过)。

2.            重构代码,运行测试并确保它们全部通过。

               

完成本实验的估计时间:60 分钟。

注意:本实验同时使用 C# 和 VB.NET 演示代码示例;但是,屏幕快照仅反映 C# 的实验操作。VB.NET 的操作与屏幕快照相似。

               

下一步

练习 1:红色、绿色…

               

练习 1:红色、绿色……

在本练习中,您将使用 Visual Studio 2010 中支持 TDD 工作流的新特性。您将了解智能标记操作、测试运行器增强和一些导航特性。

任务 1 –创建新项目

在此任务中,您将创建一个 C# 或 VB 类库和测试项目,并通过它们体验 Visual Studio 中新增的 TDD 特性。

1.            从 Start | All Programs | Microsoft Visual Studio 2010 | Microsoft Visual Studio 2010 打开 Microsoft Visual Studio。

2.            在 Visual Studio Start Page 中,单击 New Project 按钮。

 

图 1

创建项目

3.            在 New Project 对话框中,选择 Visual C# 或 VB 项目类型。确保选中了 .NET Framework 4.0,然后选择 Class Library 模板。

4.            将项目的名称更改为 SimpleDataStructures,确保选中了 Create directory for solution 复选框,然后单击 OK。

5.            删除 New Project Wizard 创建的默认 Class1.cs 文件(或 Class1.vb)。

 

图 2

删除 New Project Wizard 创建的默认文件。

6.            在 Solution Explorer 中,右键单击 SimpleDataStructures 解决方案并单击 Add | New Project…,然后选择 Visual C# | Test 或 Visual Basic | Test 项目类型。确保选中了 .NET Framework 4.0,然后选择 Test Project。

7.            将项目名称更改为 SimpleDataStructures.Tests 并单击 OK。

8.            删除 New Project Wizard 创建的 UnitTest1.cs 文件(或 UnitTest1.vb)。

 

图 3

删除 New Project Wizard 生成的默认测试文件。

               

任务 2 –为测试定义上下文。

在此任务中,您将编写一些测试来帮助设计 SimpleStack 类。

我们将创建一个新文件来保存 SimpleStack 类的一些测试,然后开始编写第一个测试。在此过程中,我们将使用新的智能标记操作来关联一些必要的导入语句,执行一些微代码生成等。

1.            在 Solution Explorer 中,右键单击 SimpleDataStructures.Tests 项目并选择 Add | Class。确保选中了 Visual C# Items | Code (或 VB.NET 中的 Common Items | Code),然后选择 Class 模板。

2.            将名称更改为 SimpleStackTests 并单击 Add 按钮。

3.            Visual Studio 将打开新的 SimpleStackTests.cs 文件(或 SimpleStackTests.vb)。您的解决方案应类似于图 4。

 

图 4

新 SimpleStackTests.cs 文件

4.       Visual Studio 会自动将新生成的类默认设置为内部类,但必须公开这些类以便测试运行器能找到并运行测试。添加 public 关键字,如以下代码所示。

C#

namespace SimpleDataStructures.Tests

{

    public class SimpleStackTests

    {

    }

}

注意:Visual Basic 默认将创建具有公共作用域的类,并且这些类文件不包含命名空间,除非您需要手动修改默认值。

Visual Basic

Public Class SimpleStackTests

 

End Class

5.            接下来,我们需要使用 TestClassAttribute 修饰这个类,以便 Visual Studio Test Runner 能将该类识别为测试窗实体。将 TestClass 属性添加到 SimpleStackTests 类。

C#

namespace SimpleDataStructures.Tests

{

    [TestClass]

public class SimpleStackTests

    {

    }

}

Visual Basic

<TestClass()> Public Class SimpleStackTests

               

End Class

6.            注意,这里存在一个问题– Visual Studio 并不能识别 TestClass 属性,因为该文件缺少一个 using 语句。

7.            您可以使用 Visual Studio 2010 中新增的智能标记操作自动纠正 using(VB.Net 中则为 Imports)语句。按下 CTRL + . 触发智能标记上下文菜单,并选择第一个选项。

 

图 5

使用智能标记添加缺失的 using 语句

8.            我们定义了一个测试实体,但在开始编写测试之前,我们需要为测试设置一些上下文。 

注意:TDD 中的“上下文”用于描述 SimpleStack 的当前条件和状态。“上下文”允许我们清楚地描述测试的目的。将测试描述为普通描述性文本而不是软件代码是非常有益的。

此外,我们将为测试实体和测试方法使用较长且更具描述性的名称。其目标是在测试的命名中传达需求的本质,并让测试主体(代码)能传达其机理。

虽然这看上去有些奇怪并且有悖于关于编写代码的一些既定的常理,但它在许多 TDD & BDD 实践中却非常有用。

9.            我们首先假定已创建了栈,这表示它处于默认状态。要设置此上下文,将 SimpleStackTests 类重命名为更具描述性的文本,比如:

C#

public class WhenAStackIsCreated

{

}

Visual Basic

<TestClass()> Public Class WhenAStackIsCreated

               

End Class

               

任务 3 –编写第一个测试:设计和定义 SimpleStack

在此任务中,您将开始设计和构建 SimpleStack 类,这需要使用任务 2 中定义的上下文创建一个测试。在此过程中,我们将使用新的智能标记操作来关联必要的 using 语句,执行一些微代码生成等。

1.            首先,创建一个新的测试方法,指明新创建的栈应该为空。使用 TestMethodAttribute 修饰该方法。注意测试类与测试方法名称之间的关系:WhenAStackIsCreated.ThenItShouldBeEmpty()。这种命名约定将帮助我们更好地理解各项测试的目的。

(代码片段 – TDD 实验 - 练习 1 ThenItShouldBeEmpty C#)

C#

[TestMethod]

public void ThenItShouldBeEmpty()

{

}

(代码片段 – TDD 实验 - 练习 1 ThenItShouldBeEmpty VB)

Visual Basic

<TestMethod()> Public Sub ThenItShouldBeEmpty()

End Sub

2.            接下来,我们需要声明并使用一个新的 SimpleStack,然后验证其 IsEmpty 属性返回值是否为 true。首先,声明并初始化一个新的 SimpleStack。

C#

[TestMethod]

public void ThenItShouldBeEmpty()

{

    SimpleStack theStack = new SimpleStack();

}

Visual Basic

<TestMethod()> Public Sub ThenItShouldBeEmpty()

    Dim theStack As New SimpleStack

End Sub

3.            注意,Visual Studio 仍然会为您提供一个智能标记,但其原因与之前不同。在本例中,Visual Studio 并不知道 SimpleStack 类是什么,因此它将为您生成一个测试存根。

 

图 6

未定义类的智能标记选项

4.            从列表中选择 Generate class for "SimpleStack"(VB.Net 则为 Generate ‘Class SimpleStack’)。此时将打开一个新窗口,并为新类生成一个测试存根。从 Solution Explorer 中打开 SimpleStack.cs 或 SimpleStack.vb 文件。

 

图 7

SimpleStack 类的测试存根

注意:上面的智能标记提供了第二个选项,即“Generate other…”,可允许您自定义要生成的代码。如果选择该选项,则会看到以下内容:

 

需要特别注意项目位置选项。默认情况下,智能标记会在当前项目中生成测试存根代码,但这并不是您所期望的行为。项目位置字段允许您在完全不同的位置创建生成的代码。

值得重点注意的是,TDD 纯粹主义者将使用智能标记方法,直接在当前工作的位置生成代码。这种精妙的设计方法支持开发人员尽可能晚地做出基本的设计选择。在我们的小型解决方案中,这显然就是保存生成的代码的位置;但是,在较大的项目中,我们可以有 20 或 30 个不同的组件。我们的代码可能需要由各种不同的组件访问。我们如何能在开发周期的早期准确知道哪些组件需要访问我们开发的代码呢?

在开发周期的晚期确定移动代码的位置,这意味着我们可以更加明确地掌控系统中的潜在依赖关系,并且能更加明智地确定保存代码的位置。所有这些都回到了最基本的原则上:通过最简单的工作让测试顺利通过。

(要了解如何在最后时刻做出关键决策,我们强烈建议您阅读 Tom 和 Mary Poppendeick 编写的 Lean Software Development 一书。)

在本例中,我们在 SimpleDataStructures.Tests 项目中触发了智能标记,但我们希望 SimpleStack 实现位于 SimpleDataStructures 项目和命名空间中。为此,我们可以在此对话框中选择相应的项目位置。

5.            返回到测试,我们将验证栈是否为空,方法是断言其 IsEmpty 属性为 true。

C#

[TestMethod]

public void ThenItShouldBeEmpty()

{

SimpleStack theStack = new SimpleStack();

 

    Assert.IsTrue(theStack.IsEmpty);

}

Visual Basic

<TestMethod()> Public Sub ThenItShouldBeEmpty()

Dim theStack As New SimpleStack

    Assert.IsTrue(theStack.IsEmpty)

End Sub

6.            您会再次看到一个智能标记,这一次用于在 SimpleDataStructures.Tests.SimpleStack 中为 IsEmpty 生成属性存根。选择此选项将在 SimpleStack 类中生成一个公共的自动属性。

 

图 9

显示创建方法存根选项的智能标记

7.            切换到 SimpleStack.cs 文件(或者 SimpleStack.vb),您将看到添加了存根的属性。

 

图 10

添加了存根的 IsEmpty 属性

8.            现在运行测试,方法是右键单击测试方法并选择 Run Tests(或键入 Ctrl+R, T)。您将看到 IsEmpty 返回 true 的断言失败了,因此测试也失败了。

9.            在 TDD 模式中,我们将通过最简单的工作让测试通过,只需要 getter 返回 true!

注意:这看上去有些不可理解;但是,它具有多个方面的重要性。首先,您将检查刚才编写的测试。如果测试未通过,则说明测试中包含错误,比如需要检查false 值时却检查了 true 值。其次,这实现了用最简单的工作通过测试的概念。

作为此概念的一部分,我们还将自动属性(可读写)修改为只读属性。我们这样做的目的在于通过最少的功能和代码来通过测试。测试并未指定需要写入栈,因此我们不会允许代码具备该功能。我们将确保代码的简洁性,这将改善易读性并减少漏洞。(代码越少意味着漏洞越少!)

C#

class SimpleStack

{

public bool IsEmpty

    {

        get { return true; }

    }

}

(代码片段 – TDD 实验 - 练习 1 IsEmpty 返回 True VB)

Visual Basic

Public Class SimpleStack

    Public ReadOnly Property IsEmpty() As Boolean

        Get

            Return True

        End Get

    End Property

End Class

10.          接下来需要返回测试;但是,您不需要将手移开键盘,而去使用鼠标。相反,借助 Quick Search 属性,您只需单击几个键就可以迅速导航到代码库。按住 CTRL + ,(即 Control 和一个逗号)触发 Quick Search 对话框,然后键入文件、类或方法的名称。Quick Search 将为您筛选出代码库中可用位置的列表。完成筛选并找到代码中的适当位置后,使用向上和向下箭头键突出显示选项并按回车键。

 

图 11

使用 Quick Search 直接导航到特定方法

注意:Visual Studio 将导航到代码库中的该位置,将光标置于类名或方法名的开始处即可!

11.          现在,您已经回到了测试方法中,重新运行测试。这次应该能顺利通过!

 

图 12

测试通过!

               

任务 4 –添加更多测试驱动的功能

此时, 我们已经完成了 SimpleStack 实现的空框架。它只有一个有效成员:一个只读属性。我们可以通过测试协助设计来继续添加功能。现在,我们来看看如何在 SimpleStack 中添加或删除项目。

1.            添加一个新测试,为 SimpleStack 指定一个新的 Push 方法,它接受整型值:

(代码片段 – TDD 实验 - 练习 1 ThenShouldBeAbleToPushAnItemOntoTheStack C#)

C#

[TestMethod]

public void ThenShouldBeAbleToPushAnItemOntoTheStack()

{

    var theStack = new SimpleStack();

    theStack.Push(1);

}

(代码片段 – TDD 实验 - 练习 1 ThenShouldBeAbleToPushAnItemOntoTheStack VB)

Visual Basic

<TestMethod()> Public Sub ThenShouldBeAbleToPushAnItemOntoTheStack()

    Dim theStack As New SimpleStack

    theStack.Push(1)

End Sub

2.            在 Push 方法调用下,您应该可以看到一个智能标记。单击 CTRL + . 触发智能标记,它允许为 Push 方法生成一个方法存根。按下回车键让 Visual Studio 生成存根。

 

图 13

使用智能标记生成方法存根

3.            现在,运行测试并确保它失败。

注意:此时运行测试看上去有些奇怪,因为我们知道 Visual Studio 添加的存根会造成测试运行失败。但是,TDD 的一个重要部分就是红色–绿色–重构的步调,而此步调中的一个关键步骤就是确保像预期那样失败。

这为何如此重要呢?因为测试难免会意外通过,这与预期不符。在这些情况下,我们需要确保测试指定了正确的行为并修复了错误的行为。

4.            我们的新目标是让此测试通过。在 TDD 模式下,我们将用最简单的工作让测试变为绿色:我们将删除 Push 方法中的 NotImplementedException!此时,我们不会向方法添加任何实现,测试仅检查是否成功推入了一些对象到栈中。

C#

internal void Push(int p)

{

}

Visual Basic

Sub Push(ByVal p As Integer)

               

End Sub

5.            使用 Quick Search (CTRL + ,) 返回调试,方法是在搜索框中输入“TSBA”。

6.            注意,Quick Search 将匹配大写字母 TSBA 与测试名称中的大写字母,并找到 ThenShouldBeAbleToPushAnItemOntoTheStack。

 

图 14

使用 Quick Search 进行筛选和导航,仅需使用类、方法或文件名中的大写字母

7.            重新运行测试,它应该能顺序通过。绿色!遗憾的是,推送方法此时的作用并不大,因此我们将在稍后继续使用它。

               

下一步

练习 2:重构!

               

练习 2:重构!

当我们刚才创建的系统代码通过测试时,可以看出它显然是没有任何意义的。现在,我们将重构这个最简单的示例,让它在通过测试的同时完成一些有意义的任务。现在,我们将进入重构阶段。

任务 1 –从通过测试转移到构建功能

1.            从 Start | All Programs | Microsoft Visual Studio 2010 | Microsoft Visual Studio 2010 打开 Microsoft Visual Studio 2010。

2.         打开 SimpleDataStructures.sln 解决方案文件。默认情况下,该文件位于以下文件夹:%TrainingKitInstallFolder%\Labs\TestDrivenDevelopment\Source\Ex02-Refactor\begin\ ,并选择您喜欢的语言。您也可以继续使用上一个练习完成时获得的解决方案。

3.            我们需要能够验证将项目推送到栈中是否能实际修改栈,也就是在 Push 操作完成后;该栈存放我们所需的对象。一种验证方法是确保栈在推入项目后不再为空。

4.            更新相应测试:

C#

[TestMethod]

public void ThenShouldBeAbleToPushAnItemOntoTheStack()

{

var theStack = new SimpleStack();

theStack.Push(1);

 

Assert.IsFalse(theStack.IsEmpty);

}

Visual Basic

<TestMethod()> Public Sub ThenShouldBeAbleToPushAnItemOntoTheStack()

Dim theStack As New SimpleStack

theStack.Push(1)

Assert.IsFalse(theStack.IsEmpty)

End Sub

5.            现在运行测试,它应该会失败。为什么会失败呢?

6.            记住,我们在 IsEmpty 实现中尽可能保证了工作的简单性,同时确保它始终返回 true 值。现在,我们需要确定 IsEmpty 的实际行为,以及它对 Push 方法的意义。

注意:测序驱动开发通常也称作测试驱动设计,其原因在于,我们将定义系统的行为,并通过设计以迭代的方式交付该行为。

7.            返回 SimpleStack 类之后,通过仔细观察,我们发现栈需要通过某种机制来存储一些状态,特别是栈所存放的项目的状态。

8.            将项目存储在列表中允许我们确定栈是否为 IsEmpty(通过检查列表的大小)。我们还可以在其中存储推入的项目。

(代码片段 – TDD 实验 - 练习 1 重构 SimpleStack C#)

C#

class SimpleStack

{

    ArrayList _items;

 

    public bool IsEmpty

    {

        get { return _items.Count == 0; }

    }

 

    internal void Push(int p)

    {

        _items.Add(0);

    }

}

(代码片段 – TDD 实验 - 练习 2 重构 SimpleStack VB)

Visual Basic

Class SimpleStack

    Private _items As ArrayList

    Public ReadOnly Property IsEmpty() As Boolean

        Get

            Return (Me._items.Count = 0)

        End Get

    End Property

    Friend Sub Push(ByVal p As Integer)

        Me._items.Add(0)

    End Sub

End Class

9.            注意 ArrayList 类型未被识别。按下 CTRL+. 并选择导入 System.Collections 命名空间。

10.          现在运行测试。您会惊讶地发现测试仍然失败了。测试失败的原因是我们未初始化 ArrayList。可以看到 Visual Studio 通过绿色的波浪式下划线提示了这个问题:

 

图 15

提醒未初始化字段的绿色波浪式线条和工具提示

11.          添加一个默认的构造函数并在构造函数中初始化列表,如以下代码所示。

(代码片段 – TDD 实验 - 练习 2 SimpleStack 构造函数 C#)

C#

class SimpleStack

{

ArrayList _items;

 

    public SimpleStack()

    {

        _items = new ArrayList();

    }

    …

}

(代码片段 – TDD 实验 - 练习 2 SimpleStack 构造函数 VB)

Visual Basic

Class SimpleStack

Private _items As ArrayList

    Public Sub New()

        Me._items = New ArrayList

    End Sub

                …

End Class

12.          再次运行测试,这次将顺利通过!

13.          我们如何知道是否存储了正确的项目呢?我们所做的全部工作就是在栈中推入了一些项目。在本例中,我们在实验的早期步骤中,为了确保简单性向栈中添加了一个零 (0) 值。

 

图 16

尽可能简单地通过测试

14.          这样做的作用并不大。我们需要实现更多功能。

15.          添加一个新测试,首先向栈推入一个项目,然后弹出一个项目,并确保我们向栈中推入了该项目。

(代码片段 – TDD 实验 - 练习 2 ThenShouldBeAbleToPushAndPopAnItemFromTheStack C#)

C#

[TestMethod]

public void ThenShouldBeAbleToPushAndPopAnItemFromTheStack()

{

    var theStack = new SimpleStack();

    theStack.Push(1);

 

    int poppedItem = theStack.Pop();

 

    Assert.AreEqual(1, poppedItem);

}

(代码片段 – TDD 实验 - 练习 2 ThenShouldBeAbleToPushAndPopAnItemFromTheStack VB)

Visual Basic

<TestMethod()> Public Sub ThenShouldBeAbleToPushAndPopAnItemFromTheStack ()

    Dim theStack As New SimpleStack

    theStack.Push(1)

    Dim poppedItem As Integer = theStack.Pop()

    Assert.AreEqual(1, poppedItem)

End Sub

16.          我们会再次看到新定义的 Pop 方法下方出现了智能标记。

 

图 17

使用智能标记生成方法存根,并使用正确的返回类型

17.          触发智能标记并让它为 Pop 方法生成一个方法存根,然后使用 Quick Search (CTRL + ,) 导航到新的带有存根的方法。

18.          注意,Visual Studio 能够确定 Pop 需要返回一个值,并且它会推断出正确的返回类型,在本例中为 int。

C#

internal int Pop()

{

throw new NotImplementedException();

}

Visual Basic

Function Pop() As Integer

                Throw New NotImplementedException

End Function

19.          运行测试,它将会失败并出现 NotImplementedException 错误,但现在我们定义了 Pop 在此上下文中的外观和行为,我们可以添加实现细节让测试通过。

(代码片段 – TDD 实验 - 练习 2 Pop 实现 C#)

C#

internal int Pop()

{

    int value = (int) _items[0];

    _items.RemoveAt(0);

 

    return value;

}

(代码片段 – TDD 实验 - 练习 2 Pop 实现 VB)

Visual Basic

Function Pop() As Integer

    Dim value As Integer = CInt(Me._items.Item(0))

    Me._items.RemoveAt(0)

    Return value

End Function

20.     再次运行测试,结果仍然会失败。这是为什么呢?Pop 方法看上去没有问题,但本机 Push 实现出现了问题,所以测试失败了。是时候解决它了!

C#

internal void Push(int p)

{

    _items.Add(p);

}

Visual Basic

Friend Sub Push(ByVal p As Integer)

    Me._items.Add(p)

End Sub

21.          运行测试,三个测试全部通过!

注意:本实验的主旨并不是深入讨论测试驱动开发的原理与实践,也不是如何正确地实现栈。

但是,如果我们继续设计和构建 SimpleStack,则需要继续思考如何在空栈上调用 Pop。此外,尝试操作满栈会出现什么问题?或者填充了一部分的栈呢?

要解决这些设计问题,我们需要在 SimpleStackTests.cs 文件中引入一些新的测试实体,以及更多测试。

此外,您可能已注意到实现中还有一个 bug!我们将项目推送到 Stack 末端,但它却从前面弹出了!我们在继续演示推入和弹出多个项目时会解决这个问题。

               

任务 2 –重组代码

有时,我们需要确定将 SimpleStack 实现从 SimpleDataStructures.Tests 项目移到 SimpleDataStructures 项目和命名空间中所需的时间。我们已在使用“Generate Other…”智能标记操作创建类的时候完成此任务(参见:练习 1,任务 #3,步骤 #2)。但是,我们选择了采用最简单的方式,并让 Visual Studio 使用默认设置,即在智能标记触发时在当前项目(SimpleDataStructures.Tests)中生成类。

1.            使用 Visual Studio Solution Explorer,从 SimpleDataStructures.Tests 项目中选择 SimpleStack.cs 文件(或 SimpleStack.vb)。右键单击并选择 Cut,然后在 SimpleDataStructures 项目中右键单击并选择 Paste。此时,Solution Explorer 应该类似于下图:

 

图 18

移动 SimpleStack.cs 文件后的解决方案结构

2.            打开 SimpleStack.cs 文件并将命名空间更改为 SimpleDataStructures。按下 Ctrl-S 保存文件。如果使用 VB.Net 则不需要此步骤。

C#

namespace SimpleDataStructures

3.            导航到测试,您会注意到所有红色的波浪线。再次返回 SimpleStack.cs 文件(或 SimpleStack.vb),并查看 SimpleStack 类的定义。当 Visual Studio 生成类之后,它会采用最简单的方式默认将类创建为内部类,因为当前只需要这样的可见性。现在,我们已经将类重构到不同的项目和命名空间中,接下来需要调整其可见性。

C#

namespace SimpleDataStructures

{

    public class SimpleStack

    {

        …

    }

}

Visual Basic

Public Class SimpleStack

                                …

End Class

4.            除了这些代码,我们还需要将 Push 和 Pop 方法的可见性更改为公共。

C#

public void Push(int p)

{

_items.Add(p);

}

 

public int Pop()

{

int value = (int) _items[0];

_items.RemoveAt(0);

 

return value;

}

Visual Basic

Public Sub Push(ByVal p As Integer)

Me._items.Add(p)

End Sub

Public Function Pop() As Integer

Dim value As Integer = CInt(Me._items.Item(0))

Me._items.RemoveAt(0)

Return value

End Function

5.            最后,我们还需要从 SimpleDataStructures.Tests 项目中引用 SimpleDataStructures 项目。在 Solution Explorer 中右键单击 References,然后选择 Add Reference。单击 Add Reference 对话框中的 Projects 选项卡,选择 SimpleDataStructures 项目,然后单击 OK。

 

图 19

添加对 SimpleDataStructures 项目的引用

6.            再次运行测试,全部测试顺利通过!

               

下一步

总结

总结

在本实验中,您了解了一些针对采用“测试优先”开发模式的开发人员的全新 IDE 增强。其中,导航改进可帮助您更加轻松快捷地在代码库中导航。IDE 可以帮助您为测试类中的方法添加存根,甚至将该代码推送到完全不同的文件中。您甚至了解了通过测试运行器查看代码和设计和状态是多么简单。

最后,或许也是重要的一点,如果您刚开始接触测试驱动设计/开发,希望您了解了如何借助 Visual Studio 采用这种激动人心的方法来创建简洁、紧凑和高质量的软件。