@BeforeClass和继承 - 执行顺序

时间:2010-01-25 14:02:46

标签: java unit-testing testng

我有一个抽象基类,我将其用作单元测试的基础(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)                // <-/

16 个答案:

答案 0 :(得分:93)

编辑:下面的答案适用于 JUnit ,但无论如何我都会留在这里,因为它可能会有所帮助。

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

我测试了这个,它似乎对我有用。

但是,正如@Odys在下面提到的那样,对于JUnit,您需要使用两个名称不同的方法,否则将导致仅运行子类方法,因为父项将被镜像。 / p>

答案 1 :(得分:38)

不要将@BeforeClass放在abstract课程上。从每个子类中调用它。

abstract class A {
    void doInitialization() {}
}

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

    @Test
    void doTests() {}
}

看起来像TestNG有@BeforeClass(dependsOnMethods={"doInitialization"}) - 尝试一下。

答案 2 :(得分:7)

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

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

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

答案 3 :(得分:6)

我刚用5.11尝试了你的例子,我首先调用了基类的@BeforeClass。

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

随时关注testng-users邮件列表,我们可以仔细查看您的问题。

- 塞德里克

答案 4 :(得分:3)

我刚刚经历过这个,并找到了另一种方法来实现这一目标。只需在摘要类中的alwaysRun@BeforeClass上使用@BeforeMethod,就可以正常工作。

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

答案 5 :(得分:2)

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

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

答案 6 :(得分:2)

对于JUnit : 正如@fortega所说: 根据JUnit api:&#34;超类的@BeforeClass方法将在当前类之前运行。&#34;

但请注意不要将两个方法命名为同名。因为在这种情况下,父方法将隐藏父方法。 Source

答案 7 :(得分: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
}

答案 8 :(得分:1)

dependsOnMethod可以使用。

e.g。如果是春天(AbstractTestNGSpringContextTests

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

答案 9 :(得分:1)

检查您的import语句。 它应该是

import org.testng.annotations.BeforeClass;

不是

import org.junit.BeforeClass;

答案 10 :(得分:0)

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

所以继承你的类的开发者被迫实现这个方法。

答案 11 :(得分:0)

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

我的特殊情况是我需要从&#34; BeforeClass&#34;中注入模拟服务。在&#34; BeforeClass&#34;之前的子类中在超类中执行。

要做到这一点 - 只需在子类中使用@ClassRule

例如:

@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
    }
};

我希望这会有所帮助。这可以在&#34;反向&#34;中有效地执行静态设置。顺序。

答案 12 :(得分:0)

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

这是我的情况

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

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

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

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

  • A.doInitialization()->从来没有默默执行过
  • B.doSpecificInitialization()
  • B.doTests()

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

这将起作用:

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()

答案 13 :(得分:0)

这对我有用-

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

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

       //do class specific init

    }   

    @Test
    doTests() {...}
}

答案 14 :(得分:-1)

在我的情况下(JUnit)我在基类和派生类中使用了相同的方法setup()。在这种情况下调用派生类的方法,并让它调用基类方法。

答案 15 :(得分:-2)

使用继承实现此目的的更好,更清晰的方法可能如下 -

abstract class A {

    @BeforeClass
    void doInitialization() {}
}

class B extends A {

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

    @Test
    void doTests() {}
}