标题：手工测试
简介
设计用例有很多原则，但是最基础的原则是覆盖性，就是要覆盖所有可能的种类（当然种类要自己区分）
例如if i〉0 then a=1 else a=0
测试用例就要在i〉0 i=0 i<0 中间各选择一个用例，比如-5 0 6，这就覆盖了所有的类型。
当然还有枚举覆盖，路径覆盖等不同的覆盖类型，还有就是要考虑到可能和不可能的类型，比如上例i=a i=“你”会怎么样，那测试用例又要增加
在测试过程中，手工测试的比重一般在30%左右。手工测试一般能够发现一些自动化测试所不能发现的问题，这也是为什么自动化测试取代不了手工测试的原因！
需要使用手工测试的场景包括以下四项：
● 如果某项测试工作难以采用自动测试完成(甚至根本无法采用自动测试完成)，例如：在程序执行的关键时刻，我们需要从物理上断开一个网络连接，其目的在于验证程序处理错误条件的能力，此时我们就可以采用手工测试。
● 对于某些测试，如果我们采用自动测试，可能导致投资回报率(return on investment，ROI)过低。例如，如果我们需要验证一个图形用户界面组件确实能够应用于某个软件产品中的某项功能的开发，而这项功能又将被其他功能替换。此时，假设使用手工测试方法只需要花费10秒时间，但是，如果使用自动测试，却需要花费几个小时甚至几天的时间编写测试，并且还要维护测试，那么在这种情况下，我们显然应该使用手工测试来解决问题。
● 需要使用自动测试，但是时间不允许进行自动测试的场合。
● 需要使用自动测试，但是开发团队当前技术水平尚不足以支持自动测试的场合。
手工测试一般是基于后面两个原因：(1)时间资源不足；(2)技术水平不足。在这些情况下，手工测试能够发挥重要的作用。利用手工测试，我们可以定义测试，还可以跟踪测试，直到这些测试因为产品变更被废弃为止。在许多开发团队中，手工测试是以工作任务清单形式存在的，而且将来可以将这些内容进行自动化——除非这个团队采用手工测试的原因是前面两个因素，即：(1)自动化是不可能的；(2)测试自动化的投资回报率太低。
探讨创建并运行一个手工测试的内部机制的过程中，我们必须记住创建手工测试的原因，和我们是如何创建手工测试的。
我们想定的场景非常简单，实际上许多测试都可以归结为一些简单步骤的集合。在本例中，用户需要验证Microsoft Outlook 2007可以顺利过渡到Disconnected(断开)状态下继续工作，同时应用程序可以将这个情况向用户报告，而且当连接断开时，不会产生有害后果。在不会引起混淆的情况下，本章后面将这个场景称为应用程序的收/发功能测试。
创建测试时，许多测试人员遇到的困难是他们无法定义一个完美的测试场景。我的建议是不要让这个困难妨碍测试，也就是说一开始测试时，我们必须抛开一些次要因素，将来可以逐步完善测试。例如，在第一个场景中，我们可以在测试过程中执行其他一些工作，举例来说，我们可以观察当网络连接断开时，应用程序需要用多长时间才能够将此情况通知用户。但是当我们进行手工测试时，一开始并不需要强调将某项功能的响应时间作为测试是否通过的标准。
编写测试时，务必对测试过程中常见的错误加以考虑。也就是说，当我们在编写测试描述及测试步骤时，必须牢记：在实际测试过程中，我们可能并不在测试现场。因此编写的测试必须尽可能地完整、尽可能地详尽。还要牢记的是：编写测试的人员未必是唯一执行测试的人员，团队中其他成员也有可能在执行某个大型测试集的过程中执行某项手工测试，有时候，由于身份变更或任务变更，编写的手工测试还有可能移交到其他人员手中。因此，我们编写测试应尽可能的完整详尽，因为这样做不仅仅是为自己，也是为其他人。举例来说，某个测试人员在执行测试过程中，当他使用一台笔记本计算机进行测试时，一方面他断开了网线与计算机的连接，另一方面他却忘记了关闭笔记本计算机与无线网络之间的连接，这时我们原本希望能够看到错误出现，然而我们却没有得到任何错误提示。显然，这个测试执行过程是不正确的。我们在编写手工测试时，必须在手工测试中描述此类问题。
编写手工测试时，首先要描述测试目的，测试环境及其局限，以及执行测试时常犯错误，然后我们需要深入到测试场景之中。此时，我们必须详细列出测试步骤。在收/发功能这个例子中，测试场景非常简单，只有三个步骤：
(1) 运行应用程序。
(2) 启动应用程序的发送/接收功能。
(3) 将网络连接物理断开。
上述步骤执行结束后，下面要描述测试的预期执行结果。在这个例子中，我们要区分程序当时是否与邮件服务器连接，因为用户界面能够显示程序状态，因此我们根据图形用户界面来判断程序状态。此时用户界面应该显示Disconnected一词。在我们最终创建的测试中，这个显示反馈的行为应该作为测试模板中的组成部分。
虽然我们仅仅给出了一个简单示例，但是只要将手工测试的其他方面考虑进来，我们就可以编写出复杂的手工测试。编写手工测试时，我们还可以考虑的其他方面包括：可访问性(此时我们要确保即使用户视力不佳，也能够及时发现其测试工具提供的用户界面所发生的变化)、可用性(在一个可控制的环境中，令用户运行测试，测试目的在于检验以下情况：当用户突然无法收发邮件时，用户是否能够马上发现网络断开)、安全性(其他应用程序是否能够利用这个功能并造成不良后果？)，以及地理政治方面的因素(当把Disconnected一词翻译为其他语言时，是否会造成误解或政治纠纷？)。
观察测试如何随时间流逝而发生演化也是一项重要工作。我们可以在测试中专门提供一个位置，在这个位置中我们可以将测试更新人员名单记录下来。这样当测试发生问题时，其他测试人员可以及时知道他们应该向谁咨询。
现在我们已经基本了解了测试场景应该是个什么样子。下面我们使用手工测试类型创建一个测试。
创建一个手工测试
手工测试类型包括纯文本格式和Microsoft Word格式，Microsoft Word格式可以支持丰富格式文本，并可以嵌入图像和表格。创建一个新的手工测试时，我们可以选择两种格式之一，如图1-1所示，这两种格式分别是：
图 1-1
● Manual Test(text format)(*.mtx)——编辑手工测试时，我们可以在IDE中用文本格式编辑测试。如果没有安装Microsoft Word，那么我们还可以使用Visual Studio编辑手工测试。
● Manual Test(Microsoft Word format)(*.mht)——我们可以使用Microsoft Word作为手工测试编辑工具。Microsoft Word为我们提供了丰富的编辑功能。例如利用这种格式，我们可以在手工测试中嵌入图像，并且可以使文字呈现多种色彩、字体、字级和风格。
1. 文本格式通过阅读本书，读者可以掌握如何通过不同的途径达到同一个目的。例如，我们既可以在Solution Explorer中用鼠标右击一个现有的项目来创建一个手工测试，也可以在Test菜单中单击New Test菜单项来创建一个手工测试。无论选择哪种方法，我们在Add New Test对话框(参见图1-1)中选中Manual Test (text format)测试类型后，系统都会弹出一个测试模板(参见图1-2)。
创建一个新的测试类型后，这个新创建的测试随即处于打开状态，现在我们可以对这个测试进行编辑。正如图1-2所示，手工测试类型也是如此。现在，Visual Studio编辑器已经打开了一个纯文本格式的手工测试，我们现在可以编辑这个手工测试了。
利用上述测试Microsoft Outlook 2007同步行为的测试示例(也就是当Microsoft Outlook 2007执行同步操作时，网络突然断开，此时我们要对Outlook的行为进行测试)，图1-3给出了一个完整的测试模板。
图 1-2
图 1-3
2. Microsoft Word格式如果我们在图1-1所示的Add New Test 对话框中选择了Manual Test (Word format)，那么系统将显示一个与图1-2类似的测试模板，唯一的区别就是我们可以使用不同的编辑工具——当前我们可以使用Microsoft Word(从图1-4可以看到，我们当前使用了Microsoft Word 2003)完成手工测试的编辑工作。图1-4说明，与纯文本格式相比，使用Microsoft Word格式可以编辑更为丰富的内容，例如我们可以嵌入屏幕快照，还可以嵌入表格和格式化文本。
图 1-4
如果我们需要对默认模板进行修改，那么我们可以在C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\ItemTemplatesCache\<language>\1033\ManualTestWordFormat.zip\目录下找到这些模板。在这个目录中，<language>表示Csharp、VisualBasic、VisualC或Test。如果我们重新进行设置，那么新的设置将覆盖ItemTemplatesCache目录下的所有内容，因此一个更好的方法是修改ItemTemplatesCache目录下的ManualTestWordFormat.zip文件。当然，如果采用了这种修改方式，那么我们必须针对每一种语言进行设置。
手工测试的属性
现在，我们在View菜单中选中Properties Window菜单项，就可以看到Visual Studio Properties窗口。在Test View窗口或Test Manager窗口中单击某个手工测试后，我们就可以在Properties窗口中看到该测试的属性。具体情况如图1-5所示。
图 1-5
如果读者当前尚未打开Test View窗口或Test Manager窗口，那么请读者在View菜单中选择Properties Window菜单项，就可以打开Test View窗口或Test Manager窗口。
我们可以将当前测试的任意一个属性添加到Test View窗口或Test Manager窗口中，这样，我们可以基于该属性的属性值对手工测试进行过滤或分组。
一个手工测试包括表1-1所示的属性。
表 1-1
属 性可 编 辑 性描 述Associated work items如果该属性为VSTFS的组成部分，那么该属性为可编辑的当我们在一个开发团队中工作时，如果开发项目连接到一个Visual Studio Team Foundation Server，那么一个工作项将与一个测试相关联。工作项可以包括多种内容，例如在一个工作项中，可能包括一个等待完成的任务，还可能包括一个产品缺陷(即bug)。通过将一个工作项与一个测试关联起来，我们可以将一个测试直接映射到这个产品的特定领域。（如果读者需要了解如何在与一个VSTFS项目连接的条件下进行测试，请参考本书第9章内容）Deployment Items可编辑的在运行测试过程中，利用这个属性，我们可以确定部署的文件或文件夹。我们可以在同一行代码中指定文件或文件夹的访问路径，也可以为每个文件或文件夹分别用一行代码指定访问路径。我们还可以在测试运行配置中确定文件和文件夹的访问路径（见第2章内容中对Test Run Configuration对话框的介绍说明）。此外，我们可以在部署项中重新定义相关访问路径，也可以添加新的访问路径Description可编辑的使用该属性，我们可以描述当前测试的目的ID 只读的这个属性是为每个测试所赋予的唯一标识符。如果一个测试是一个手工测试类型，那么其ID就是这个测试驻留的实际路径Iteration如果该属性为VSTFS的组成部分，那么该属性为可编辑的当我们在一个开发团队中工作时，如果当前开发项目连接到Visual Studio Team Foundation Server，那么我们可以定义一个“迭代”。我们可以将一个“迭代”视为软件开发生命周期(SDLC)的一个里程碑（或一个阶段）。利用这个属性，我们可以指定当前测试所属的软件开发生命周期阶段Non-runnable Error只读的如果某个测试是一个测试项目的组成部分，但是由于某些原因，在某次测试运行时这个测试并没有执行，那么我们可以用这个属性来描述这个问题。例如如果本地驱动器上的文件并不存在，但是一个测试项目需要使用这个文件，那么就可以用这个属性描述这种情况Owner可编辑的这个属性用于说明编写测试或维护测试的用户的IDPriority可编辑的如果开发团队使用了这个属性，那么可以利用这个属性确定优先运行哪些测试Project只读的这个属性用于描述当前测试所属的父项目的名称(续表) 
属 性可 编 辑 性描 述Project Area如果该属性为VSTFS的组成部分，那么该属性为可编辑的如果某个团队开发的项目连接到了Visual Studio Team Foundation Server，那么测试可以直接映射到TFS中为这个项目开辟的一个区域。这个属性用于指定这个区域Project Relative Path只读的这个属性包含了测试所属项目的文件名。此处的路径是一条相对于本地磁盘上的解决方案位置的相对路径Solution只读的这个属性是包含了当前测试所属测试项目的解决方案的名称Test Enabled可编辑的当一次测试运行包括了某个测试时，我们可以利用这个属性，在不修改这次测试运行的前提下将这个测试排除在这次测试运行之外。例如，我们可以关闭一个可能导致当前构建的应用程序崩溃的测试，直到该应用程序的新版本修正了导致程序崩溃的bug之后，我们再重新启用这个测试，从而将这个测试重新纳入这次测试运行中Test Name只读的这个属性为测试名称，一般是基于文件名定义的Test Storage只读的在手工测试中，测试存储与测试ID是相同的，也就是说，测试存储就是这个测试驻留的实际路径Test Type只读的这个属性为测试的类型，在此，测试类型为手工测试。我们可以将当前测试的任意一个属性列添加到Test View窗口或Test Manager窗口中，这样我们可以根据属性值对测试进行分组或过滤。所以利用这个属性我们可以观察所有的手工测试Timeout只读的这个属性确定了测试的超时值。手工测试类型不包括超时的时限值，也就是说：对手工测试类型而言，超时值为无穷大。对于其他测试类型，我们可以用超时的时限值来规范测试执行时间。如果测试在规定的超时时限内没有正常运行结束，那么我们认为这个测试执行失效如果读者需要了解如何在连接到一个Visual Studio Team Foundation Server项目的情况下完成测试工作，请阅读第9章的内容。
执行一个手工测试
执行测试时最常用的两个窗口分别是Test Manager窗口(该窗口仅在VSTEST中可用)和Test View窗口(该窗口在VSTEST和VSTESD中均可用)。我们可以通过选择Test菜单中的Windows菜单项打开Test View窗口。如果读者创建了两个手工测试，那么在打开Test View窗口后，在Test View窗口中，读者可以看到两个手工测试，这两个手工测试都称为ManualTest1。具体情况请参见图1-6。
图 1-6
用鼠标右击Test Name属性列(也可以单击Test View窗口中的任意一列属性)，我们可以从下拉菜单(也就是上下文菜单)中选中Add/Remove Columns菜单项。此时系统弹出Add/Remove Columns对话框(参见图1-7)。这个对话框用一个列表显示了所有的属性，我们可以对这些属性进行排序(我们只要单击该列表的标题就可以完成排序操作)、过滤(需要输入一个关键词，并选择一个属性列，针对该属性列，利用这个关键词进行过滤)和分组(因为该窗口很小，所以可以单击Test View窗口最右端的工具条上的overflow按钮，然后选中对测试进行分组的属性就可以完成分组操作)。
图 1-7
为了解释如何在Test View窗口中增加一列属性，以及如何根据某个属性对测试进行分组，下面我们用一些测试对此进行说明。首先我们在测试项目中添加一些测试，将Owner属性显示为一个属性列，然后在Group By位置处，选择测试类型(参见图1-8)。
图 1-8
我们在Test View窗口中执行的所有操作都同样可以应用于Test Manager窗口，但是，正如我们在第2章所讨论的那样，在Test View窗口中，我们还可以将测试分组为不同列表。
执行一个手工测试与执行其他测试没有什么不同。为了选中一个测试，我们可以在Test Manager窗口中或在Test View窗口中单击一个测试，如果需要选中多个测试，那么在按下Shift键的同时，我们可以选中鼠标两次单击范围内的所有测试；此外在按下Ctrl键的同时，我们还可以选中一组不同的测试。
选中测试后，单击Test Manager窗口中或Test View窗口中的工具条上的Run Selection图标。令鼠标指针在工具条每个按钮上方悬停片刻，我们可以观察到每个按钮的描述信息，从而可以了解该按钮的具体功能。
我们知道，在Visual Studio中，为了完成某项工作，可以采用多种不同的方法。观察窗口中的工具条，我们可以发现，对于某项通过单击工具条按钮可以完成的操作，通过用鼠标右击属性列或对象后，利用上下文菜单，同样可以完成这项操作。此外，当我们在一个窗口中工作时，主窗口一般都会为我们提供一个工具条，帮助我们在当前窗口迅速完成工作。这一点对测试也同样成立：主窗口菜单下方的Test Tools工具条可以帮助我们在测试窗口中迅速完成相关工作。为了显示Test Tools工具条，我们可以在View菜单中选中Toolbars子菜单，然后再选择Test Tools菜单项，就可以显示出Test Tools工具条。
启动执行手工测试之后，我们马上可以看到一个信息提示，通知我们当前运行的测试包含了一个手工测试(参见图1-9)。出现这个信息提示的原因是：当我们执行一组测试时，如果当前运行的测试包含了一个手工测试，那么运行这些测试的测试人员可以没有意识到这种情况将会导致测试发生暂停。有的时候，测试人员启动一个大型测试之后去吃午饭，然而，当他们吃完午饭后返回办公室时却发现，他们离开后大概一分钟，测试就已经暂停下来等待手工干预，这种情况确实令人非常不快，常常使人充满了挫折感。
图 1-9
测试开始执行后，Visual Studio将读取当前测试的运行配置信息(我们在第2章讨论了运行配置信息)，从而可以确定需要复制那些文件，是否需要插装被测试程序来收集代码覆盖信息等内容。Visual Studio根据测试列表中的内容，一个接一个地执行测试，当遇到一个手工测试时，将显示一条诸如“Manual Test ‘manualtest1’ is ready for execution”(手工测试manualtest1已准备好执行)之类的信息。此时，测试暂停并等待测试人员根据手工测试步骤一步步地完成手工测试过程，测试人员需要根据他们所观察到的结果判断该手工测试是否通过。在Visual Studio IDE中，手工测试显示为一个标签文档(tabbed document)，与图1-10中所显示内容非常类似。
图 1-10
这个标签文档包括四个部分的内容：
● Apply工具条按钮——只有当测试人员单击了该文档中Select Result分组部分中的Pass or Fail选项按钮后，这个按钮才会成为活动的。
● Select Result分组——在这个分组中包括两个选项按钮，即Pass选项按钮和Fail选项按钮。利用这两个选项按钮，测试人员可以确定手工单步执行测试脚本的测试结果。
● Comments文本框——在这个文本框中输入的信息可以保存为测试结果，如果测试发生失效，那么测试工程师可以在这个文本框中输入更为详细的失效信息。
● 测试脚本视图——这个标签文档窗口的底部给出了测试脚本的内容。测试人员可以利用Visual Studio内置的文本编辑器或Microsoft Word编写测试脚本。
如果读者使用Microsoft Word编写手工测试，那么当测试执行时，请读者注意测试人员所看到的表格和嵌入图片的显示方式。纯文本格式的测试版本可能会对相关内容进行大幅度简化。
测试人员确定测试输出结果后，单击Apply按钮，随即可以看到如图1-11所示的Test Results窗口，这个窗口显示了测试输出结果。单击Apply按钮后，用于为测试人员显示手工测试脚本的标签文档窗口也同时变为只读的。现在这个文档窗口已经成为当前运行测试历史的组成部分了。
图 1-11
最后，我们说明一下手工测试类型存在的不足之处(此处所说的不足之处，系指除了需要人工交互之外的其他不足之处)。如果某个测试需要在远程计算机上运行，那么手工测试是不能作为这个测试的组成部分的；此外，如果某个测试被配置为验证一个团队完成的某个构建的稳定性，那么这类测试无法作为这个测试的组成部分来执行；最后，这类测试无法用命令行工具(即mstest.exe)来执行。之所以存在这些问题，其根本原因都是因为手工测试需要人工干预，而我们很难远程执行手工测试，也就是说，这个功能要求执行测试的远程计算机停止运行，并且在继续执行之前提示用户采取行动。因为这会导致无法事先预料的测试暂停(因为测试人员可能会忘记测试中包括了手工测试)，而团队也常常没有时间来解决这些方面的问题，所以我们可以采用的唯一解决方案是：将手工测试步骤打印出来，带到实验室，然后在某台合适的计算机上运行手工测试。完成测试后，返回办公室，在本地计算机上运行手工测试，然后根据测试过程中发现的情况，将测试结果标记为Passed或Failed。确实，这种方法不是最优方法，但是在产品开发时间的限制下，我们常常无法及时实现手工测试，所以我们也只能采用这个办法。