如何在测试失败后但在任何 @After 方法之前让 JUnit 4.8 运行代码?

Posted

技术标签:

【中文标题】如何在测试失败后但在任何 @After 方法之前让 JUnit 4.8 运行代码?【英文标题】:How can I make JUnit 4.8 run code after a failed test, but before any @After methods? 【发布时间】:2012-01-23 18:01:25 【问题描述】:

我正在使用 JUnit 4.8.2 进行一套 Selenium 测试(实际上是 WebDriver 支持的 Selenium)。我希望测试在断言失败后立即自动截取浏览器的屏幕截图。所有的测试都继承自SeleniumBaseTestCase,然后大部分都进​​一步继承自SeleniumBastTestCaseWithCompany(它使用@Before@After 方法通过Selenium 创建并清理公共测试数据)。

我尝试在SeleniumBaseTestCase 中添加TestWatchman 的子类作为@Rule,覆盖TestWatchmanfailed 方法来截取屏幕截图。问题是@After清理测试数据的方法是在TestWatchmanfailed方法被调用之前运行的,所以截图都是清理的最后一步,而不是失败的测试.

稍微看了一下,好像TestWatchmanapply方法只是调用了传递过来的Statement的evaluate方法(唯一暴露的方法),它调用了@After方法,留下了@987654339 @(或任何其他 Rule)据我所知,没有机会在测试的执行和 @After 方法的执行之间插入任何代码。

我还看到了创建自定义 Runner 以更改创建的 Statements 的方法,以便使用自定义 @AfterFailure 注释的方法在 @After 方法之前运行(因此可以在这样的情况下截取屏幕截图一个@AfterFailure 方法),但这依赖于覆盖BlockJUnit4ClassRunnerwithAfters 方法,根据documentation,该方法已被弃用并且将变为私有,它建议改用规则。

我在 SO 上找到了另一个关于 @Rule lifecycle 的答案,听起来这在 JUnit 4.8 中可能根本不可能,但在 JUnit 4.10 中可能是可能的。如果那是正确的那么公平,我想先确认一下。

任何关于我可以实现我想要的优雅且面向未来的方式的想法将不胜感激!

【问题讨论】:

【参考方案1】:

您的分析是正确的,@Befores 和 @Afters 被添加到任何规则之前的语句列表中。 @Before@Rule 之后执行,@After@Rule 之前执行。如何解决此问题取决于您使用SeleniumBaseTestCaseWithCompany 的灵活性。

最简单的方法是删除您的@Before/@After 方法并用ExternalResource 替换它们。这可能类似于:

public class BeforeAfterTest 
    @Rule public TestRule rule = new ExternalResource() 
        protected void before() throws Throwable  System.out.println("externalResource before"); 
        protected void after()  System.out.println("externalResource after"); 
    ;

    @Test public void testHere()  System.out.println("testHere"); 

这给出了:

externalResource before
testHere
externalResource after

这个字段可以放在你的基类中,所以它会被继承/覆盖。你在@After 和你的规则之间排序的问题就会消失,因为你可以使用@RuleChain(在 4.10,而不是 4.8)按你喜欢的方式排序你的规则。

如果你不能改变SeleniumBaseTestCaseWithCompany,那么你可以扩展BlockJUnit4ClassRunner,但不要用Afters覆盖,而是覆盖BlockJUnit4ClassRunner#methodBlock()。然后,您可以调用 super.methodBlock,并根据需要重新排序语句 [*]。

[*]您可以只复制代码,然后重新排列行,但 withRules 是私有的,因此不能从子类调用。

【讨论】:

是的,我认为升级 JUnit 是可行的方法——我在 4.8.2 中看不到特别令人满意的解决方案。我在SeleniumBaseTestCase 上有一个受保护的 TestWatcher 来截取屏幕截图,以及一个以它为唯一规则的 RuleChain。然后在 SeleniumBaseTestCaseWithCompany 我有一个 ExternalResource 来创建/删除公司,并且我隐藏了超类的 RuleChain 来排序屏幕截图和创建/删除规则。似乎工作得很好,谢谢。 只是一个注释。在 4.11 中,您将能够在方法上指定 @Rule,因此您可以覆盖该方法而不是隐藏字段。但是4.11还没有发布。

以上是关于如何在测试失败后但在任何 @After 方法之前让 JUnit 4.8 运行代码?的主要内容,如果未能解决你的问题,请参考以下文章

单击后但在重定向之前刷新/重置链接/WPushButton 的 WResource

如何让浓缩咖啡测试在特定条件下失败

解决sklearn找不到模块(安装后但导入失败)

JUnit @Before和@After在每次测试之前和之后执行[重复]

测试时导致问题的任务

Flyway 迁移在 MS SQL Server 中成功,但在 H2 数据库中失败