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

Row*_*wan 10 java junit selenium junit4 selenium-webdriver

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

我已经尝试添加一个子类TestWatchman作为@Rulein SeleniumBaseTestCase,overriding TestWatchmanfailed方法来截取屏幕截图.问题是在@After调用方法之前正在运行清理测试数据TestWatchmanfailed方法,因此屏幕截图都是清理的最后一步,而不是失败的测试.

寻找到它一点点,看来TestWatchmanapply方法只是调用传递Statement的评估方法(只露法),它调用的@After方法,使TestWatchman(或任何其他Rule)没有机会插入测试的执行之间的任何代码@After据我所知,这些方法.

我也看到了创建自定义Runner以改变Statement创建的s的方法,以便在方法@AfterFailure之前运行使用自定义注释的@After方法(因此可以在这样的@AfterFailure方法中截取屏幕截图),但这依赖于覆盖BlockJUnit4ClassRunnerwithAfters方法,这是根据文档建议弃用且由于变为私有,建议使用规则.

我在SO上找到了关于@Rule生命周期的另一个答案,这听起来似乎在JUnit 4.8中可能是不可能的,但在JUnit 4.10中可能是可能的.如果那是正确的那么公平,我只想先确认一下.

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

Mat*_*ell 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"); }
}
Run Code Online (Sandbox Code Playgroud)

这给了:

externalResource before
testHere
externalResource after
Run Code Online (Sandbox Code Playgroud)

此字段可以放入基类中,因此可以继承/覆盖它.您在@After和规则之间订购的问题就会消失,因为您可以使用@RuleChain(在4.10而不是4.8中)按照自己的喜好订购规则.

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

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