@BeforeClass和继承-执行顺序


90

我有一个抽象基类,用作我的单元测试(TestNG 5.10)的基础。在该类中,我将初始化测试的整个环境,设置数据库映射等。此抽象类具有一个带有@BeforeClass注释的方法,该方法可以进行初始化。

接下来,我用具有@Test方法以及@BeforeClass方法的特定类扩展该类。这些方法对环境进行类特定的初始化(例如,将一些记录放入数据库中)。

如何执行带@BeforeClass注释的方法的特定顺序?我需要先执行抽象基类中的那些,然后再执行扩展类中的那些。

例:

abstract class A {
    @BeforeClass
    doInitialization() {...}
}

class B extends A {
    @BeforeClass
    doSpecificInitialization() {...}

    @Test
    doTests() {...}
}

预期订单:

A.doInitialization
B.doSpecificInitialization
B.doTests

实际订单:

B.doSpecificInitialization // <- crashes, as the base init is missing
(A.doInitialization        // <---not executed
 B.doTests)                // <-/

Answers:


50

不要把@BeforeClass上的abstract类。从每个子类调用它。

abstract class A {
    void doInitialization() {}
}

class B extends A {
    @BeforeClass
    void doSpecificInitialization() {
        super.doInitialization();
    }

    @Test
    void doTests() {}
}

好像TestNG一样@BeforeClass(dependsOnMethods={"doInitialization"})-试试看。


9
这基本上就是我要避免的事情:无需显式调用super(抽象)类的方法。特别是因为我也有一些类,这些类继承自A但没有自己的@BeforeClass方法。我只需要为此插入一个。
多米尼克·桑贾贾

5
dependsOnMethods解决方法奏效了。尽管我更喜欢“超一流”的方法……
Dominik Sandjaja 2010年

1
要使用“ dependsOnMethod”,不应将“ doInitialization”注释为“ @Test”吗?这是一个问题,因为从技术上讲,它本身并不是测试...
N3da 2014年

@BeforeClass应该注释一个静态方法
Fabrizio Stellato '19

108

编辑:下面的答案是针对JUnit的,但是无论如何我都会将其保留在这里,因为它可能会有所帮助。

根据JUnit api:“超类的@BeforeClass方法将在当前类之前运行。”

我对此进行了测试,它似乎对我有用。

但是,正如@Odys在下面提到的那样,对于JUnit,您需要将两个方法命名为不同的名称,否则这样做将导致仅运行子类方法,因为父类将被遮盖。


56
即使最初的问题是针对TestNG的,但在搜寻了JUnit之后我还是来到了这里,您的回答有所帮助-谢谢!
–teabot

9
对于JUnit,您需要将两个方法命名为不同的名称,否则,这将导致仅运行子类方法,因为父类将被遮盖。
奥德斯(Odys)

2
@Odys,非常感谢您提到这一点。我正在努力弄清为什么子类中的“ setup”方法正在运行而其父类中的“ setup”方法却没有运行。您刚刚救了我一大堆麻烦!
汤姆·卡图罗

你让我今天一整天都感觉很好。谢谢!
突袭

7

我将其添加public到抽象类中,然后TestNG(6.0.1)在之前执行了doInitialization()doTestsdoInitialization()如果我public从A类中删除,TestNG将不会执行。

public abstract class A {
 @BeforeClass
 doInitialization() {...}
}

class B extends A {    
 @Test
 doTests() {...}
}

1
没错,但这无关紧要。当class B 具有@BeforeClass-annotated方法时,这将不起作用,例如在OP中。
jpaugh

1
我也一样 如果基本方法是私有的,则似乎错过了继承顺序。谢谢!
Manu

6

我只是用5.11尝试了您的示例,然后首先调用了基类的@BeforeClass。

您可以发布您的testng.xml文件吗?也许您在此处同时指定了A和B,而只需要B。

请随时关注testng用户的邮件列表,我们将仔细研究您的问题。

-塞德里克


2
没有为testng定义.xml(明确地),它是从Eclipse和Maven运行的。
多米尼克·桑贾贾

您如何从Eclipse确切地运行它?右键单击B类?
塞德里克·贝斯特

4

我刚刚经历了这一过程,并找到了另一种方法来实现这一目标。只需在抽象类alwaysRun@BeforeClass@BeforeMethod在抽象类中使用,即可按预期工作。

public class AbstractTestClass {
    @BeforeClass(alwaysRun = true)
    public void generalBeforeClass() {
        // do stuff
        specificBeforeClass();
    }
}

2

当我从以下位置运行时:JUnitCore.runClasses(TestClass.class); 如果您从Eclipse运行它,它将 在子级之前正确执行父级(您不需要super.SetUpBeforeClass();):由于某种原因,它无法运行基类。解决方法:显式调用基类:(BaseTest.setUpBeforeClass();)如果从应用程序运行基类,则可能需要在基类中有一个标志,以确定它是否已设置。因此,如果您通过两种可能的方法(例如,从eclipse进行个人测试,并通过ANT进行构建发行)运行,则只能运行一次。

这似乎是Eclipse的错误,或者至少是意外的结果。



1

如何让@BeforeClass方法调用一个空的specificBeforeClass()方法,该方法可能会或可能不会被子类覆盖,如下所示:

public class AbstractTestClass {
  @BeforeClass
  public void generalBeforeClass() {
    // do stuff
    specificBeforeClass();
  }

  protected void specificBeforeClass() {}
}

public class SpecificTest {
  @Override
  protected void specificBeforeClass() {
    // Do specific stuff
  }

  // Tests
}

3
BeforeClass必须为静态,因此您无法使用junit做到这一点
madx

1

dependsOnMethod 可以使用。

例如在Spring(AbstractTestNGSpringContextTests)的情况下

@BeforeClass(alwaysRun = true, dependsOnMethods = "springTestContextPrepareTestInstance")

1

检查您的进口声明。它应该是

import org.testng.annotations.BeforeClass;

import org.junit.BeforeClass;


1

这对我有用-

abstract class A {
    @BeforeClass
    doInitialization() {...}
}

class B extends A {
    @Override
    @BeforeClass
    doInitialization() { 

       //do class specific init

    }   

    @Test
    doTests() {...}
}

1
添加这段代码的简短说明并回答原始问题
Cray

0

为什么不尝试在您的超类中创建抽象方法doSpecialInit(),该方法从超类中的BeforeClass注释方法调用。

因此,继承您类的开发人员必须执行此方法。


老实说,自从我问这个问题以来,甚至在过去的3.5年中,逻辑也可能发生了变化... ;-)所以,是的,也许这是一个主意,也许没有用-老实说,我没有记得。
Dominik Sandjaja 2013年

0

这里还有另一个简单的解决方案。

我的特殊情况是,在执行超类中的“ BeforeClass”之前,需要从子类中的“ BeforeClass”注入模拟服务。

为此,只需@ClassRule在子类中使用a 。

例如:

@ClassRule
public static ExternalResource mocksInjector = new ExternalResource() {
    @Override
    protected void before() {
        // inject my mock services here
        // Note: this is executed before the parent class @BeforeClass
    }
};

我希望这有帮助。这样可以有效地以“反向”顺序执行静态设置。


0

我今天遇到了类似的问题,唯一的区别是基类不是抽象的

这是我的情况

public class A {
    @BeforeClass
    private void doInitialization() {...}
}

public class B extends A {
    @BeforeClass
    private void doSpecificInitialization() {...}

    @Test
    public void doTests() {...}
}

发生了@BeforeClass从未执行过类A 的方法的情况。

  • A.doInitialization()->从未默默执行
  • B.doSpecificInitialization()
  • B.doTests()

在使用隐私修饰符时,我发现如果从类继承程序中看不到@BeforeClass方法,则TestNG 将不会从继承的类中执行带注释的方法

所以这将工作:

public class A {
    @BeforeClass
    private void doInitialization() {...}
}

public class B extends A {
    @BeforeClass
    //Here a privacy modifier matters -> please make sure your method is public or protected so it will be visible for ancestors
    protected void doSpecificInitialization() {...}

    @Test
    public void doTests() {...}
}

结果发生以下情况:

  • A.doInitialization()
  • B.doSpecificInitialization()
  • B.doTests()

-1

就我的情况(JUnit)而言,我在基类和派生类中具有称为setup()的相同方法。在这种情况下,调用派生类的方法,而我将其称为基类方法。


-2

使用继承来实现此目的的更好,更干净的方法如下:

abstract class A {

    @BeforeClass
    void doInitialization() {}
}

class B extends A {

    @Override
    @BeforeClass
    void doInitialization() {
        super.doInitialization();
    }

    @Test
    void doTests() {}
}

1
如果您需要首先执行Parent类中的方法,则只需在Child类中为该方法命名,而不要使用Parent的名称(因为如果它们具有相同的签名,那么多态性就会起作用)。我相信这是一种更清洁的方式。
Anatolii Stepaniuk '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.