我们正在开发测试代码(主要是使用一些不同工具的UI测试)。让我感到困扰的一件事是如何最好地将测试数据与测试脚本分开。通过测试数据,我的意思是输入到AUT中的值。

目前,我有一堆类,它们仅在方法中包含测试数据。这几乎可以正常运行,但是


不能扩展,并且不能从测试代码外部进行修改。

我们已经讨论了一些方法,例如将数据保存在测试数据数据库中,在这些数据中脚本需要时调用不同的数据。这可能是要走的路,但是我不知道如何实现它。其他人成功使用了哪些方法?我希望测试脚本尽可能地与传入数据无关。

EDIT有关这些测试的更多详细信息:所有测试数据都是从外部源传递的参数(不同的类,xml,数据库等)插入测试代码。这些测试是用Java编写的。

评论

嗨,joshin,要给出一个很好的答案,我需要更多信息:您的测试相对较小的独立项目还是您有很多依赖项? (依赖关系=需要知道我拥有的项目,然后才能选择其大小,并且我的数据涉及根据项目ID进行查找)。如果要将参数传递给类,则几乎可以肯定是后者。

@KatePaulk这些测试旨在相互独立,但是数据中存在依赖关系(数据类型2取决于数据类型1,这两个数据我都需要为测试指定)。正如您所提到的,我似乎有很多依赖项。

joshin4colours:为什么要从测试代码外部修改测试数据?为什么测试脚本必须与传入数据无关?

#1 楼

查看您的测试框架是否为您提供参数化测试的方法。许多测试框架允许您使用自己编写的“数据提供程序”方法或对象或类来提供值。如果您有这样的框架,请查看是否可以使用其数据提供程序机制来提供值。

通常的机制是您的代码从某个地方获取值,并将其交给测试框架。作为某种类似于网格的东西(列表列表,数组数组,数组可迭代)。网格的每个“行”都代表一次测试执行的值。

在TestNG中这很容易,并且在JUnit中可能(有点儿麻烦)。

尽可能将这些值存储在纯文本文件中。这样做的原因是,您可以将数据与测试一起放入版本控制中。通常,一个CSV文件会做的很好,而且对于您用来自动执行测试的任何语言,都有很多CSV阅读器库。任何类型的二进制数据文件(Excel,数据库等)都无法与版本控制一起使用。

评论


JUnitParams库简化了在JUnit中创建参数化测试的过程。

– dzieciou
13年8月26日在18:20



为了简化以CSV或XML划分的测试数据的处理,请将它们映射到Java Bean。将OpenCSV或SuperCSV用于CSV(请参见此处的示例),将JAXB用于XML测试数据。

– dzieciou
13年8月31日在16:08



#2 楼

您可以在此处采取两个主要方向。用户X,导航至订购,选择产品B的数量A,产品D的数量C,结帐,使用卡明细Y支付,并检查所有金额是否正确加总并到达了应该去的地方)


任何基于文件的结构都可以在这里工作。您可以使用大多数测试工具中内置的数据驱动线束,在其中定义数据提供程序并指向资源。框架将为每一行遍历资源一次。
您可能需要添加额外的列或字段,并在脚本中添加对空列/字段的处理,但是它仍然非常轻巧且无故障。
CSV尤其有用,因为您可以轻松地进行版本控制它。您还可以在内部管理CSV布局,以便轻松分辨哪些数据属于哪一列(如果这样做,则不要使用Excel进行编辑,因为Excel会删除为提高可读性而添加的前导/后缀空格-数据您将不需要经常进行编辑,因为它易于在文本文件中读取具有很大的区别)
将预期结果作为CSV文件进行比较也相对容易,这样您的验证就不难了-编码。您可以将其作为单独的基线CSV进行操作,也可以在文件中包括期望值的列/字段。
如果可以通过这种方式进行操作,这是数据驱动脚本的最简便方法。

如果您的脚本通过多个参数化例程执行单个场景(例如,主处理程序例程,该例程将用户名和密码传递给登录例程,然后调用购买例程,该例程又将数量和产品传递给选择项目例程,然后将付款数据传递给购买例程,然后返回到主例程,该例程调用金额和存储数据检查例程)


这种结构倾向于在有许多测试用例具有相似的功能,但是对于每个序列结构和数据而言,对于单个脚本而言,它们的闭合度还不够。例如,如果某种购买会提示您提供更多信息,而不是重复整个登录/选择代码(该代码不会改变),则每个步骤或通用步骤序列都将分解为一个参数化例程,该例程将由主设备调用控制器。
并非所有测试工具都支持这种参数化模型。可以使用一些大型工具(只要您通过代码接口进行工作并将其视为纯编程的测试代码)即可完成,但并非全部都可以。
只要维护大量的文档,CSV和其他平面文件结构仍然可以在这里使用,因为您最终将在文件中建立关系数据库(我怎么知道?我已经做到了)。这使版本化成为可能,但可能给新的自动化人员带来陡峭的学习曲线,他们不仅必须熟悉众多可用的例程和控制结构,还需要了解数据文件与代码结构的关系。
如果您不介意大量重复数据(如果有必要修改多个文件中使用的内容的话,这绝对是一件痛苦的事),那么像XML这样的更结构化的文件格式可能是可行的,并且再次易于版本控制。
最终,管理此类测试数据的最佳方法是通过数据库,最好是具有编辑前端。您可以使用Access Forms之类的方法来执行此操作,也可以构建Intranet前端-或绑定到数据库的小型应用程序。在这种情况下,版本控制变得更加复杂,因为数据库在版本控制中不能很好地发挥作用。我的首选方法是在数据库表中包含版本控制信息,以便每个表都有一列,例如“ ValidFrom”,“ ValidTo”,其中标有首次有效的AUT版本。这样可以使脚本避免从错误的版本中提取资源,尽管这又增加了另一层复杂性。
如果您确实需要针对这种测试结构的数据库解决方案,则备份是必不可少的。您还需要复制主测试数据库,以免针对实时数据开发新的功能测试(并可能破坏计划的脚本)并构建要更新的合并脚本。这需要做很多工作-但是具有合理的前端优势,这使得非脚本编写者可以向系统中添加新的测试用例。
当您的测试代码库变得足够大以至于您无法再在多个测试中维护几乎相同的代码时,或者当您的AUT过于复杂以至于任何测试都需要多个几乎相同的步骤之前,这种级别的测试结构就变得至关重要到达您实际上对测试感兴趣的系统区域。
即使采用这种结构消除了大多数重复的代码,您仍然可以保留很多代码:在我以前的雇主中,自动化代码库是按顺序排列的的1/2万个LOC
,并在多个文件中维护了相同数量的CSV数据行,并且对其版本进行了严格的版本控制。这是合理的
成熟的测试自动化工作-测试自动化已在
实现某种形式已经使用了10多年,并且已经从记录/播放
发展到参数化的记录/播放代码版本,将多个面向对象的,数据驱动的脚本代码迭代成表格
那是我离开的时候。它不是为胆小的人而设计的,它最终变得必不可少了(在这种情况下,AUT是由7个核心应用程序组成的套件,其中主要的应用程序上次具有超过200万个LOC
)任何人都检查过,有数百个配置标志,并且对于许多大型企业来说都是至关重要的-我们不能
不能错过任何交易或税收处理方面的问题。

那应该使您对选择数据驱动策略有更多的了解。

评论


+1用于定义测试数据中的预期结果。我们在学院中使用了这种方法来定义参考判断或黄金标准。它确实简化了算法评估的自动化,因此我想它也可能对工业有所帮助。

– dzieciou
2013年8月26日19:16



@dzieciou-我发现这样做非常重要,因为需要防止测试代码库爆炸。如果我们走更标准的路线,由于应用程序的复杂性和自动化的需求,我们将拥有数百万行几乎相同的脚本代码。向其中添加验证结果将是可怕的-实际上,为税收回归更新基准可能需要数天的痛苦。

–凯特·保罗(Kate Paulk)
13年8月27日在11:54

如果您想向测试数据架构中添加新参数,我认为解决方案中的任何解决方案都无法很好地扩展。特别是,如果您希望已有前端输入测试数据,则需要在所有层中添加新参数:数据库,业务逻辑和用户界面。其他类型的修改相同。

– dzieciou
13年8月31日在17:33



@dzieciou-我们提出了一种稍微不同的方法来处理此问题。如果我们需要在现有数据中添加新列,则该列将具有描述性名称。因为每个类加载器都使用通用名称,字段名称和列名称,并将其全部视为字符串,所以除非您想显式进行强制转换,否则无需进行修改。因此,唯一需要更改逻辑的地方就是UI-脚本结构化,因此它们也将忽略UI端的额外字段。我可以(并确实)添加了一些新的列处理,并带有一些空默认值的复制/粘贴,一行数据和一个代码。

–凯特·保罗(Kate Paulk)
2013年9月1日19:16

不错的方法!可以说这是技术细节,但不是:这是可伸缩性要求的基础。

– dzieciou
2013年9月1日19:29



#3 楼

除了Dale提出的建议之外,还可以使用Java编码测试数据。

这将满足您的所有要求:


可以在超出测试代码的范围内进行修改。如果您在单独的Java类中定义了测试数据,则无需将它们与测试脚本类一起编译。您可以在运行时将其链接为Java Bean,例如使用Spring。显然,您知道将测试数据放在单独的文件中将需要在窗口之间切换,因此捕获测试数据与预期行为之间的关系将变得更加困难。
与测试数据无关的测试脚本。首先,测试脚本将与测试数据的原始格式无关,因为它们将依赖Java Bean(或它们的接口)的getter方法,而不是数据如何进入Java Bean。因此,您可以从使用Java设计测试数据开始,如果您改变主意(转而使用数据库,XML或CSV文件),则可以轻松地将这些测试数据源映射到Java Bean(例如,使用一个我在Dale的回答下建议的图书馆)。其次,测试脚本将无法确定数据的来源。它将由@DataProvider方法或类决定,它将从以下位置读取测试数据:Spring上下文在运行时定义的数据库,外部文件或Java Bean。

可扩展。添加新的测试数据可以很好地扩展。例如,您可以定义一个包,其中@DataProvider在运行时扫描新的测试数据。由于采用了封装,它也可以很好地扩展大小域。如果您不希望使用大型类,则可以将无关的详细信息隐藏到超类,助手类等中。例如,我们编写createReturnTicket()而不是

createTicket().with(Type.Return).from("New York").to("Los Angeles") 


从测试案例的角度来看,我们并不在乎机票是从纽约到洛杉矶。这些是此方法的内部细节,如果透露这些细节,则会使图片模糊。 XML划分的测试数据不能很好地扩展域的大小。当我们有非常大的XML文件时,真的很难理解它们的描述,或者给定两个大的XML文件,它们之间有何不同。


我知道有些人反对这种方法,因为他们是商人,而不是程序员,所以害怕在Java类中编码测试数据。此外,XML文件也有其优势,特别是当AUT通过设计处理XML时。商界人士更熟悉用于描述应用程序数据的XML标准。重现生产中的许多问题相当容易:您只需从生产中分离出一个XML文件样本,然后将它们复制到我们的测试存储库中即可。

但是,在双方的共同努力下,能够解决其中一些问题,同时仍获得使用纯Java方法的优势。方法如下:


设计类和方法来很好地描述您的域,这通常称为嵌入式DSL(特定于域的语言),例如createReturnTicket()是我们DSL的一种方法示例。
设计DSL时,请通过封装,专用方法等隐藏不相关的细节。
使用具有流畅接口的Builder模式(另请参见本主题的另一篇文章)和静态导入。这样,您将获得IDE和Java编译器的大力支持,以定义正确的测试数据:自动完成,语法高修饰和验证。
提供示例测试用例和测试用例编写会话,以便人们可以学习如何编写测试案件。

连续重构DSL,因此在学习域时变得易于使用。与XML / CSV或数据库方法相比,使用Java测试数据时,在拥有大量现有测试数据时更改测试数据结构相对简单。


评论


我没有完全阅读您的答案,它是我的答案的更好版本,因此我将删除我的:-)我个人更喜欢将测试数据保留在代码中并使用DataProvider支持。

–山姆·伍兹(Sam Woods)
13年8月26日在18:41

#4 楼

我已经为我们的SaaS应用程序编写了2个自动化框架,这些框架将键/值对作为URL查询(包括幕后的事物)并动态地渲染图像。

无法解决的原始框架

第一个是在PHP中使用目录存储测试脚本的目录,该脚本包含测试数据并使用共享功能为回归套件创建测试用例。过一会儿,这是不可扩展的,并且取决于谁蘸了手指来编写这些脚本,太多的事情可能出错。当时这是一种方便的方法,它只能放入脚本并在下一次计划的运行中执行它。案件和内存泄漏。该机器人将为URL查询调用x个随机修饰符,然后,该修饰符将调用相关函数为URL创建有效的键/值对。

新Java框架

最近,我用Java重新编写了这个框架,并决定从小处着手,并使用数据库作为测试数据URL。该数据库还存储回归运行结果,关联的Java Web App可以查看和钻取回归结果。

我使用Hibernate与命令行和Java Web App的数据库进行通信,效果很好。我有一个Servlet,它将通过POST或GET接受命名查询或HQL语句(赋予数据钻取页面更大的自由度,以使质量检查人员可以通过URL查看库存查询结果或自定义结果)并吐出JSON,从而使数据钻取页面变成可读的组织数据。

到目前为止,此框架对于非脚本化质量检查而言效果更好。我给他们提供了一个excel电子表格和一个wiki页面,介绍了如何填写它们,他们只输入了数据,然后将其与脚本一起插入到数据库中。我打算为此创建一个Web UI,以在提交之前显示请求呈现,以便非脚本质量检查人员可以自己插入测试。

运行此套件的工作流程:


手动运行Java命令行应用程序,或通过Jenkins运行Java命令行应用程序,该程序将使用一个配置文件来告诉它运行的各种选项/功能。 ,
用于存储转储文件的位置,以及要用于比较的2台服务器(该套件没有基准)。
将调用数据库以获取所有测试记录并进行编译
将它们减去请求server:port放入一个平面文件中。创建
平面文件还可以确保我们在需要时可以再次运行完全相同的测试。
然后逐行读取平面文件,形成每个文件的完整URL请求
。服务器。然后,根据返回的
,将响应相互比较,以了解
感知差异或text / xml / json差异。
每个请求结果都写入结果文件,转储文件br />每个请求都被存储。运行结束时,将解析结果文件,收集服务器数据,并将其插入数据库中,以供Java Web App拾取并使用
用于管理的图形。

我们用Java编写的其他框架

我们还有其他各种用Java编写的框架,它们可以像现在所使用的那样简单地运行测试数据。测试方法。我发现这有点杂乱无章,很难搜索现有的测试以查看是否要复制测试用例。然后,必须为测试方法名称确定一个命名约定并对其进行缩放。另外,您不能进行非脚本/编程的QA插入测试,而每次有新的/修改的测试时都必须进行构建。

另一个小组有一个类似的Java框架,使用Junit进行执行,并使用XML文件作为测试数据。这些XML文件包含大量数据,并且有许多XML文件涵盖它们测试的API。如果我不知道自己在寻找什么,我将无法提供帮助,并且可能最终会导致重复测试。另外,如果XML模式发生变化,则必须找出安全的搜索并替换所有这些XML文件。

评论


欢迎来到SQA Deirdra!您能否在答案中总结一下您的解决方案如何解决有问题的要求?可扩展性,可否从测试脚本之外修改和删除测试脚本?

– dzieciou
13年8月31日在17:30

#5 楼

我建议您查看Builder模式,以便在测试脚本中创建测试数据。

类似于将数据存储在脚本中,但是所需的数据不是经过硬编码的实际数据。从理论上讲,测试可以在任何环境中运行,因为测试可以创建自己的数据。

我经常认为拥有外部数据源是有风险的,就像输入数据不正确一样,则测试不正确。该测试假设提供的数据是正确的,因为构建器模式意味着该测试完全知道该数据处于什么状态,因为它创建了它。

我仅考虑使用Data Providers进行测试是数据驱动的(例如,确保大范围的值返回相同的响应)。但是,我的大多数测试似乎都是由场景驱动的,因此看不到如何使用数据提供程序。如果我的测试想要针对该场景的特定状态的数据,那么我希望我的测试以所需的状态创建该数据。

评论


我认为这取决于预期结果是硬编码,在数据提供程序中进行参数化还是即时计算。

–user246
13年8月27日在3:29

我认为这还取决于应用程序的性质:在您使用已知的输入模式对用户进行了培训的情况下(例如用于特定目的的企业对企业应用程序),将输入和验证数据存储在外部以简化更新很有意义-特别是在有很多情况时(税收回归...数千个订单仅在税收情景中有所不同-所有结果均不同,但相差不大。数据文件为数千行CSV)

–凯特·保罗(Kate Paulk)
13年8月27日在12:05

@KatePaulk,有成千上万行CSV,如何阅读和维护?您怎么知道您已经涵盖了哪种情况?

– dzieciou
13年8月31日在21:22

@dzieciou,每个测试方案都有一个ID列和一个注释列。注释列用于描述正在执行的测试。因此,对于税收回归测试,可能会出现ID = 55,注释=“免税的客户出售5倍交易性税收零售项目然后无效”的维护问题,但一旦我们创建了所有税收,就很少获得新税收场景。

–凯特·保罗(Kate Paulk)
2013年9月1日19:12在

@ KatePaulk,+ 1非常清楚。为测试用例名称找到一个既描述又简短的约定是一个单独的问题。超有趣”。

– dzieciou
2013年9月1日19:24在