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

时间:2011-12-19 16:17:43

标签: java selenium selenium-webdriver junit junit4

我正在使用JUnit 4.8.2驱动一套Selenium测试(实际上是WebDriver支持的Selenium)。我希望测试在测试失败时自动截取浏览器的屏幕截图。所有测试都继承自SeleniumBaseTestCase,然后大多数继承自SeleniumBastTestCaseWithCompany(使用@Before@After方法创建,然后通过Selenium清理常见测试数据)。

我尝试在TestWatchman中添加@Rule的子类作为SeleniumBaseTestCase,覆盖TestWatchman的{​​{1}}方法来截取屏幕截图。问题是在调用failed @After方法之前正在运行TestWatchman方法来清理测试数据,因此屏幕截图都是清理的最后一步,而不是失败的考验。

稍微调查一下,似乎failed的{​​{1}}方法只调用传递的TestWatchman的evaluate方法(唯一公开的方法),它调用{{ 1}}方法,让apply(或任何其他Statement)没有机会在执行测试和@After方法之间插入任何代码,据我所知。

我还看到了创建自定义TestWatchman以更改所创建的Rule的方法,以便在@After方法之前运行使用自定义Runner注释的方法(因此屏幕截图可以在这样的Statement方法中获取),但这取决于覆盖@AfterFailure的{​​{1}}方法,该方法已被弃用且由于变为私有,根据{{ 3}},建议使用规则。

我在SO上找到了关于documentation的另一个答案,这听起来似乎在JUnit 4.8中可能无法实现,但在JUnit 4.10中可能是可能的。如果那是正确的那么公平,我只想先确认一下。

对于我能够实现我想要的优雅和面向未来的方式的任何想法将不胜感激!

1 个答案:

答案 0 :(得分:7)

您的分析正确,@ 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,但不要覆盖withAfters,而是覆盖BlockJUnit4ClassRunner#methodBlock()。然后,您可以调用super.methodBlock,并根据需要重新排序语句[*]。

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