在编写自动化测试时,我遇到一种情况,即在一种方法中包含多个验证点,但随后我也读/听过一种测试应仅进行一种验证。您遵循哪种方法,为什么?

n.b.我的指针可以用一种方法进行多次验证,一旦得到满意的答复,便会详细说明。
我好像又提出了一个主观/议论性的问题。

评论

您是否真的在第一句话中表示“俱乐部”?我不是没有幽默感;我只是认为这可能是一个错字。你是说“团块”吗?

大声笑,我的意思是“俱乐部”。在我这个世界俱乐部中,这也意味着“将事物捆绑在一起” ....

好吧,今天我学到了一些新东西。我将把“ club”更改为“ include”,这在我们两个世界中都意味着正确的事情。

同意,感谢您这样做,我希望看到这些评论,没人希望它被发布到堆栈溢出的“ grammer”站点:-)

#1 楼

我将多个验证合并到一个测试中,但只允许在执行测试的某一时刻进行。测试工具可以从失败的验证中正常恢复(验证绝不能更改IMO状态;如果收集数据更改状态,请在测试过程中收集数据或将该验证作为另一个测试),然后继续执行其他验证。


为什么要进行多次验证?



如果导致故障的错误是可重复且一致的,则下次将再次重复并导致与以前相同的验证失败。如果每次的结果都一样,为什么要浪费设置时间?
如果导致故障的错误不能重复且不一致,那么我想收集关于该特定故障的尽可能多的信息-最好完成多次验证。


为什么只在测试中的某一时刻使用它们?



安装失败与测试失败不同实际测试,而我的测试工具对它们的处理方式有所不同。我也可以轻松地以不同的方式报告它们,并且这些信息对于业务决策很有用。
如果测试B依赖于测试A而测试A失败,则无法解决测试A的错误来修复测试B因为这将更改测试A。如果A和B是单独的测试,那么我可以重写测试B的设置以解决测试A中的错误,而又不影响测试A。例如,如果A发布评论,而B正在查看a从另一个帐户发布评论,并且由于评论“提交”按钮的JavaScript损坏而导致发表评论失败,我仍然可以通过直接在安装程序中更新数据库,然后验证是否已正确提交评论来测试B,从而测试B将能够查看它。


编辑添加:我刚刚意识到臭名昭著的“ Given-When-Then”格式遵循相同的规则。您有一个测试(“何时”部分),当“何时”完成后,您可以使用“ and”关键字验证多个“ then”语句。因此,有一个方法可以解决这个问题。


评论


所以这就是我要做的(这是我在发布问题时不想透露的内容)。当涉及到页面的UI验证时,我将它们合并(哎呀,我的意思是“ include” :-)),并且我的测试方法会报告一个或多个缺少元素的失败。但是对于更多的“逻辑检验”,我总是有不同的方法。确定+1

–塔伦
2011年6月15日在16:45

#2 楼

我个人喜欢原子测试,通常设计为仅测试一两个项目,大多数验证在测试用例本身中被显式调用。这样一来,您可以轻松地在高层查看正在验证的内容,例如(从parkcalc中)。

    [TestMethod]
    public void InvalidTextAsExitDate()
    {
        Parking.Calculate(ParkingType.LongTermSurfaceParking, "12:00", "AM", "today", "12:00", "AM", "INVALID");
        Verify.SpecificErrorIsShown(ErrorMessages.EnterCorrectDate);
    }

    [TestMethod]
    public void OnlySpecifyEntryDate()
    {
        Parking.Calculate(ParkingType.LongTermSurfaceParking, "12:00", "AM", "today", "12:00", "AM", "");
        Verify.VerifyResult(ParkingType.LongTermSurfaceParking, "12:00", "AM", "today", "12:00", "AM", "");
    }


每当我将验证推到较低层时,我一直在想,“这到底在验证什么”,例如

    [TestMethod]
    public void OnlySpecifyExitDate()
    {
        Parking.CalculateAndVerify(ParkingType.LongTermSurfaceParking, "12:00", "AM", "", "12:00", "AM", "today");
    }


那么下一个层次是

    public static void CalculateAndVerify(ParkingType parkingType, string inTime, string inAMPM, string inDate, string outTime, string outAMPM, string outDate)
    {
        Calculate(parkingType, inTime, inAMPM, inDate, outTime, outAMPM, outDate);
        Verification.Verify.VerifyResult(parkingType, inTime, inAMPM, inDate, outTime, outAMPM, outDate);
    }


我的框架的完整工作示例解决方案可在以下位置获得: https://github.com/teknologika/stax

评论


我完全同意-尤其是当您有大型应用程序时,一眼就能知道测试的工作状态很重要。

– CBA
2011年6月15日在11:37

我非常希望您给出了“向下验证级别”的伪代码

–塔伦
2011年6月15日13:22

@tarun示例发布:-)

–布鲁斯·麦克劳德(Bruce McLeod)
2011年6月16日于1:23

#3 楼

另一个缺点是在一个测试中合并太多的东西,就是失败可能阻止其他验证的发生。

假设您将三个验证合并,第二个失败。您的自动化会停止吗?还是继续三个?三个有多重要?如果您可以在没有得到验证的情况下生活,那么合并将节省时间。但是,如果将三个要验证的事情放在首位,那么我会自行考虑并花点时间。

评论


如果您利用测试失败后继续执行测试(尤其是在您想要这样做时)并将所有故障报告在测试报告中怎么办?

–塔伦
2011年6月15日13:25

理想情况下,您的测试工具可以区分同一测试中的10个失败和10个测试中的每个失败,因为一个测试中的第一个失败可能会标记一个条件,该条件必然导致同一测试中另外9个失败。

–user246
2011年6月15日15:52

为了即使在失败之后也要继续执行测试,我们应该使用验证而不是断言。断言失败后,Assert停止整个测试用例执行,并继续验证并将其报告为失败

– Aruna
2011年6月15日17:53

#4 楼

对于单元测试,我非常喜欢每次测试测试一件事。原因是:当测试失败时,我希望测试将我尽快指向损坏的代码。

如果一个测试测试了多个项目,那么测试的名称是不够的指向损坏的代码。我必须寻求其他信息,例如堆栈跟踪,它可以将我引导到一行测试代码。然后,我必须查看测试代码行,以了解它在做什么以及在什么上下文中使用。现在,这不是我遇到过的最可怕的问题,但是...

如果测试测试了一件事情,那么失败测试的名称通常足以使我朝着正确的方向前进。 。并非总是如此,但经常如此。

出于不同的原因,我也更喜欢使每个验收测试成为一件事情。但是在这里,我的理由主要是清晰。我希望每个验收测试都能清楚地描述其测试的功能或职责。我想看看为什么这个测试很重要。测试做的事情越多,就越难理解测试的重点。

我更有可能放宽对验收测试的偏爱,尤其是通过GUI或浏览器进行测试时。启动和拆卸有时会花费很长时间。如果我在每个测试中做更多的工作,那么我执行的那些长时间运行的设置和拆卸操作将更少,因此套件需要的时间更少。另一方面,每个测试都需要花费更长的时间才能运行,并且如果该测试已嵌入更大的“创建frobozz,对其进行编辑,保存,删除”测试中,则无法仅对“创建新的frobozz”内容进行测试。 。

评论


请参阅您的观点Dale,是的,我指的是基于浏览器的自动测试。我的问题应该很清楚:-<

–塔伦
2011年6月15日下午13:28

如果单元测试只检查一件事,那么它们可以更快地指出损坏的代码。

– Ethel Evans
2011年6月16日17:44



#5 楼

我知道这似乎有些奇怪,但这要视情况而定。我处理的许多测试都涉及完成定义的交易(转到此位置,选择物料Y的数量X,以付款方式Z进行支付)-对于我使用的自动化,这构成了一个测试。

我工作的团队发展以更好地了解问题起源的方式之一是如何构造脚本化的错误处理-脚本代码中的每个方法都具有异常处理,并且任何异常将使用文件名和例程名称记录日志,因此记录的内容可能看起来像这样:“无需授权时,将显示“ TransactionLib.RunTransactions:TransactionLib.TransactionStep:PaymentLib.MakePayment:PaymentLib.CashPayment:授权表”。

在可能的情况下,我们尝试从中进行恢复,从而使测试运行得以完成,尽管它将使基线数据不同步,并导致许多比较差异-此处的原因是,如果问题的原因是可以配置或作为应用程序一部分的东西,它不应停止测试运​​行,如果发生访问冲突或类似级别的错误,那一切就掉了,并立即将其修复。

我们的框架旨在执行其设置,运行定义的一组事务测试(我们将其有效地存储在csv文件的关系数据库中),然后进行详细的基准检查并执行清理。这是否算作单独运行每个测试还是将它们全部串在一起,将取决于准确定义“测试”的方式。

每个测试都可以使用大量的代码例程中的几个,并且我们尝试在可能的情况下将其限制在一个动作中。每个测试步骤也可能涉及多个代码例程,具体取决于正在执行的操作-再次,这很大程度上取决于您的被测试应用程序。小型Web应用程序几乎不需要我刚刚描述的复杂程度:我大部分时间都在处理具有一百万行代码的大型复杂应用程序。

简短版本:如果您可以快速诊断问题并找出解决方法,则测试的结构无关紧要-尽管如果其他人可以学习诊断和解决问题会有所帮助问题也很快。

#6 楼

我在一个测试方法中包含了多个验证点,原因如下:


在对元素执行任何操作之前,我首先要验证该元素是否在页面上首先。 UI控件有重命名或删除的可能性。相同的逻辑也适用于页面。在执行任何测试之前,我会通过验证页面标题来验证我是否在正确的页面上。因此,我在一个测试方法中有多个验证点。我首先验证我是否在正确的页面上,然后验证是否存在所需的UI控件,然后执行测试用例的预期验证点。
可以将某些验证点逻辑上组合在一个测试方法中。例如,当我在facebook上测试“发表评论功能”时,我有两个验证点。一种是验证评论是否成功发布,另一种是验证我的朋友是否可以阅读我刚刚发布的评论。由于这两个验证点在逻辑上是相关的,因此将它们组合在一个测试方法中是有意义的。声称他人无法阅读我的评论是正确的。


#7 楼

我假设OP打算将“验证点”表示为一种条件,其评估确定测试是否失败,例如什么测试框架通常称为“断言”。

在确定被测代码是否准备就绪时,您可能只关心对“每个测试都通过了”这个问题的二进制答案。对于所有其他时间,您的测试有两个目的,我称之为验证和诊断。验证是在检查软件是否满足要求。诊断正在缩小导致故障的特定条件。

这种双重性通常是测试人员和开发人员之间紧张的根源。如果测试人员没有采取其他措施,则他们必须决定产品是否通过测试。如果测试失败,则开发人员必须更改一些代码(如果没有其他要求)。在这两个事件之间,必须由某人确定导致失败的多种情况中的哪一种情况是必要和充分的。有了这些信息,开发人员将考虑这些情况如何映射到代码。在此之前,可能需要考虑一下这种情况是否经常发生或足够重要以证明需要进行更改。

浏览任何产品的错误跟踪系统,您可能会看到紧张的迹象。在验证和诊断之间。由于症状“太模糊”或“不够具体”,开发人员将错误反馈给测试人员。一个测试人员花了很多时间来重现问题,想知道为什么懒惰的开发人员无法自己诊断问题。

那么这如何应用于自动化测试?在单个测试中使用多个验证点可增加其诊断价值。如果我需要f()返回true,g()返回1,h()返回3以通过测试,则开发人员将很高兴知道这三个条件中的哪一个失败。
使用多个验证点还有其他原因。有时,测试会包含“健全性检查”:这些条件可能表明测试中的错误假设(例如资源的可用性),而不是被测代码中的问题。您还可以使用多个验证点,因为设置费用证明同时执行多个测试是合理的,尽管这样做可能会降低测试的诊断价值。 (实际上,我们每天都会做出这种妥协;大多数人不会为每个测试重建整个测试环境。)

评论


+1用于显示验证点如何对诊断产生影响

– Aruna
2011年6月15日在16:34

#8 楼

将多个条件合并到一个测试用例中的另一个原因只是缩短了运行时间。
在我们的系统设置中,每个测试的拆除可能要花费一两分钟以上的时间,如果乘以100个测试用例,则总计为大量。当我说“设置和拆卸”时,我指的是测试框架时间本身,因此对于一堆测试(通过慢速网络和慢速服务器进行的分布式测试框架)一次也不能跳过它。

评论


我想你的意思是“可以保存”,不是吗?

–塔伦
2011年6月15日13:23

#9 楼

老实说,这实际上取决于您要测试的产品暂存区的距离。

作为开发人员进行测试时,您可能正在为测试驱动的开发进行简单的单元测试,是的,您应该真正做一个测试=一个功能验证。

但是越走越远,您想要结合的越多,因为您确实想测试大多数软件产品的整个状态机,并且您确实想结合奇怪的事情。

因此,您将从测试一个简单功能的基本测试开始,然后逐步构建到一个真正试图涵盖所有内容的主测试(通常是性能/耐力/扩展测试)。

#10 楼

就个人而言(我非常相信这是正确的方法),我始终只能通过单元测试来达到一个测试条件。始终无一例外。
对于集成和验收测试,我的目标是击中尽可能少的测试条件,以行使被测组件或功能。可能正确的测试条件数量实际上可能很多(特别是对于大型测试),但是更高级别的测试中越来越多的测试条件数量会导致自动测试变得脆弱并且至关重要,从而导致失败更难以解释。
为了在编写这些高级测试时专心致志,我牢记着一个问题:“我实际上在尝试检查什么?”。如果有足够重要的测试条件可以添加到自动检查中,但与我当前编写验收测试的内容没有直接关系,则可以将这些条件用作新的单独测试用例的基础。

#11 楼

仅适用于小型测试套件

我改变了我的观点,即随着时间的推移,每个测试仅声明1条规则。

几年前,进入质量检查在现场,我认为这是一个很好的方法,几乎​​无法解释和证明。正如其他张贴者所写的那样,它是具体说明所测试的内容,更具体的故障等的方法。

但是我已经看到在现实世界中,最重要的是随着测试套件的增长,由于以下原因,将其作为固定的规则变得有问题:


测试套件的运行长度。如果所有测试都必须执行设置和拆除(应该这样做),并且仅测试1断言,则可能导致测试套件时间非常长。这是一个巨大的问题,因为一旦测试套件变慢,就会发生很多坏事(无法运行,开发缓慢,对共享种子数据的使用增加等)。
测试套件的大小。如果编写了3个测试,共有19个断言,则对这些测试进行更改相对容易。但是,如果使用这19个断言将测试分解为19个测试,而每个测试只有1个断言,则对于许多程序员而言,维护和更新代码将容易出错,费时且无聊。
不干。当许多示例重复相同的设置和拆除操作时,您会开始在很多地方需要大量剪切和粘贴编程和代码,而无需在一个地方进行更新。我经常看到“某些”测试的设置发生了变化,而没有将这些更改应用于其他测试,从而导致样式混乱。程序员有不同的见解和经验。我与许多不遵循“每个测试1个断言”规则的程序员一起工作。使每个规则都遵循这个规则将是一个挑战(在某些组织中值得,但在其他组织中则不值得)。

注意:“多个声明”的示例是,对于给定的UI操作,人们可能期望


在特定屏幕上显示
在特定位置查看某些数据
查看正确的错误消息
查看正确的操作按钮以继续
查看数据库正确更新。

所以这是同一动作的5个断言。

我同意并发现麻烦的一件事是@ethal evans提到“只允许他们在同一时刻执行测试。“
我也希望将它们放在测试结束时(任何必要的拆卸除外)。