一尘不染

Selenium + JUnit:测试顺序/流程?

selenium

我正在使用Selenium来测试我的Java
Web应用程序的html页面(实际上是JSP)。我的网络应用程序需要访问每个页面的流程(这是一个小型的在线游戏网络应用程序),例如:要进入页面B,您需要进入页面A,输入一些文本,然后按一个按钮进入页面。
B.显然,我已经进行了一些测试来验证A页是否正常工作。

我希望能够编写更多测试,以便在运行A页的测试之后检查是否可以运行B页的测试(其余的应用程序依此类推)。简而言之:以某种方式在测试中定义一些顺序。

在最近几天阅读了大量有关测试的内容之后,我找不到关于此特定主题的任何有趣信息。因此,我现在正在寻求建议。

我确定的可能解决方案:

  1. 为页面A定义(在同一测试类中)测试方法,然后为测试B定义测试方法。然后命令执行测试方法。但是我们知道JUnit(但TestNG允许)不允许测试方法执行排序,请参见问题selenium-junit-tests-如何执行测试-我按顺序进行测试

  2. 将所有测试(针对A页,B页等)组合在一种测试方法下。但是我读到它很不好,看到这样的问题:junit一个方法每个方法案例或多个方法每个方法案例。做selenium测试不好吗?我看过一些代码在做,所以我认为可能不是。

  3. 将所有测试(针对A页,B页等)组合到一个测试方法下,但使用JUnit的ErrorCollector类:ErrorCollector允许您以相同的方法执行有序的检查,如果一个测试失败则产生特定的错误消息,但让方法(因此进行检查)一直运行到结束。这种解决方案对我来说似乎太“残酷”了。

  4. 使用JUnit的TestSuite类:它按照套件中定义的测试类的顺序运行套件中列出的测试。因此,这涉及到使用独立的测试方法来测试测试类中的页面A(比如说TestA),然后使用所有测试方法来测试测试类中的页面B(比如说TestB),依此类推。然后将其插入到测试套件中,例如@SuiteClasses({TestA.class,TestB.class,TestC.class,…})

  5. JUnit的TestSuite类与JUnit的ErrorCollector类结合使用。哦,好吧,既然可以,您可能希望对每个页面进行不同类别的分组测试,并且在该分组页面的顶部使用ErrorCollector测试“区域”。如果您的网页非常密集或其他原因,此解决方案可能非常有用。

  6. 相当基本:使用其他工具(如TestNG)可以访问诸如测试方法排序之类的功能。

注意:我想有些人会推荐最后一个解决方案(迁移到TestNG),但我也想听听与JUnit相关的其他想法/意见。例如,如果我正在一个因某种原因而无法迁移到另一个测试框架的团队中工作,那么他们将如何解决这个测试订购问题?


阅读 283

收藏
2020-06-26

共1个答案

一尘不染

为什么要迁移?您可以使用JUnit进行单元测试,并使用另一个框架进行高级测试。在您的情况下,这是一种接受,功能或端到端的方式,命名方式并不重要。但是重要的是要了解这些测试
不是
单元。它们遵循不同的规则:它们更复杂,运行时间更长,频率更低,它们需要复杂的设置,外部依赖关系,并且可能偶发性地失败。为什么不为它们使用其他框架(甚至是另一种编程语言)?

可能的变体是:

如果不能添加另一个框架:您为JUnit枚举了更多选项,那么我可以想象=)我会将整个流程的测试脚本放在一个测试方法中,并将测试代码组织到“
Drivers”中。这意味着您的端到端测试不会直接调用应用程序或Selenium
API的方法,而是将它们包装到Driver组件的方法中,这些方法隐藏了API的复杂性,并且看起来像是对将要发生的事情或预期的事情的声明。看例子:

@Test 
public void sniperWinsAnAuctionByBiddingHigher() throws Exception {
    auction.startSellingItem();

    application.startBiddingIn(auction);
    auction.hasReceivedJoinRequestFrom(ApplicationRunner.SNIPER_XMPP_ID);

    auction.reportPrice(1000, 98, "other bidder");
    application.hasShownSniperIsBidding(auction, 1000, 1098);

    auction.hasReceivedBid(1098, ApplicationRunner.SNIPER_XMPP_ID);

    auction.reportPrice(1098, 97, ApplicationRunner.SNIPER_XMPP_ID);
    application.hasShownSniperIsWinning(auction, 1098);

    auction.announceClosed();
    application.hasShownSniperHasWonAuction(auction, 1098);
}

摘录自“ 测试指导的不断增长的面向对象软件
”。这本书真的很棒,我强烈建议您阅读。

这是使用真正的XMPP连接,Openfire jabber服务器和WindowLicker Swing
GUI测试框架的真正的端到端测试。但是,所有这些东西如果都卸载到驱动程序组件中。在测试中,您仅看到不同参与者之间的交流方式。它是有序的:在应用程序开始竞标之后,我们检查拍卖服务器是否收到加入请求,然后指示拍卖服务器报告新价格并检查它是否反映在UI中,依此类推。整个代码可在github上找到

github上的示例很复杂,因为该应用程序并不像书本示例中那样平凡。但是那本书逐渐地给了它,我能够按照本书的指南从头开始构建整个应用程序。实际上,这是我读过的有关TDD和自动化开发人员测试的唯一一本书,它提供了这样详尽而完整的示例。我已经阅读了很多。但是请注意,驱动程序方法不能使您的测试成为现实。它只允许您隐藏复杂性。而且它也可以(也应该)与其他框架一起使用。它们只是为您提供了其他可能,如果需要,可以将测试分为多个顺序步骤。编写用户可读的测试用例;将测试数据外部化为CSV,Excel表,XML文件或数据库,以使测试超时;与外部系统,servlet和DI容器集成;定义并分别运行测试组;提供更人性化的报告等。

关于使所有测试单元。除了诸如数学,字符串处理等实用程序库之类的东西以外,其他任何事情都是不可能的。如果您的应用程序经过了完全的单元测试,则意味着您不能测试所有应用程序,或者您不了解哪些测试是单元测试,哪些不是。第一种情况可能不错,但是开发人员,测试人员,用户或其他任何人都必须手动测试和重新测试未涵盖的所有内容。这很普遍,但是最好是有意识的决定,而不是随便的决定。为什么不能对所有内容进行单元测试?

单元测试有很多定义,这会引发神圣的战争。)我更喜欢以下内容:“单元测试是对程序单元进行隔离测试。”
有人说:“嘿,单元是我的应用程序!我测试登录,它是简单的单元功能”。但也有一些语用学 孤立地
藏起来。为什么我们需要区别于其他单元测试?因为这是我们的第一个安全网。他们必须快。您经常提交(例如,到git),并且 至少 运行它们 __每次提交之前。
但是想象一下,“单元”测试需要5分钟才能运行。您可以减少运行它们的次数,也可以减少提交的次数,或者一次只运行一个测试用例甚至一种测试方法,或者等待每2分钟说一次,以便在5分钟内完成测试。在这5分钟之内,您将进入编码恐怖,接下来的2个小时将在其中度过=)并且单元测试决不能偶尔失败。如果他们这样做-
您将不会信任他们。因此,需要进行隔离:您必须从单元测试中隔离缓慢性和偶发性故障的根源。因此,隔离意味着单元测试不应使用:

  • 文件系统
  • 网络,套接字,RMI等
  • 图形用户界面
  • 多线程
  • 外部库需要测试框架并支持Hamcrest等简单库

并且单元测试必须是本地的。当您在2分钟的编码中出现缺陷时,只希望一个或多个测试失败,而不是整个套件的一半。这意味着您在单元测试中测试状态行为的能力非常有限。您不应该进行使5个状态转换达到先决条件的测试设置。因为第一次转换中的失败将破坏至少4个针对后续转换的测试,以及当前为第六次转换编写的另一个测试。而且,任何非平凡的应用程序中都有很多流程和状态转换。因此,这不能进行单元测试。出于同样的原因,单元测试一定不能在数据库,静态字段,Spring上下文等中使用可变的共享状态。这正是JUnit为每个测试方法创建测试类的新实例的原因。

因此,您看到,无论如何重新编码,都无法完全对Web应用程序进行单元测试。因为它具有流程,JSP,Servlet容器,甚至还有更多。当然,您可以忽略该定义,但它非常有用。)如果您同意将单元测试与其他测试区分开是有用的,并且该定义有助于实现这一目标,那么您将选择另一个框架或至少另一种方法不属于单元的测试,您将为各种测试创建单独的套件,依此类推。

希望这会有所帮助)

2020-06-26