@BeforeClass和继承 - 执行顺序

问题描述 投票:82回答:16

我有一个抽象基类,我用它作为单元测试的基础(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)                // <-/
java unit-testing testng
16个回答
39
投票

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

abstract class A {
    void doInitialization() {}
}

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

    @Test
    void doTests() {}
}

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


1
投票

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

import org.testng.annotations.BeforeClass;

import org.junit.BeforeClass;


0
投票

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

继承您的类的开发人员是否被迫实现此方法。


0
投票

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

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

要做到这一点 - 只需在子类中使用@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
    }
};

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


0
投票

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

这是我的情况

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

0
投票

这对我有用 -

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

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

       //do class specific init

    }   

    @Test
    doTests() {...}
}

-1
投票

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


-2
投票

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

abstract class A {

    @BeforeClass
    void doInitialization() {}
}

class B extends A {

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

    @Test
    void doTests() {}
}

94
投票

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

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

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

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


7
投票

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

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

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

6
投票

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

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

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

- 塞德里克


3
投票

我刚刚完成了这个,并找到了另一种实现这一目标的方法。只需在抽象类中使用alwaysRun@BeforeClass上的@BeforeMethod,就像你期望的那样工作。

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

2
投票

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

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


2
投票

对于JUnit:正如@fortega所提到的:根据JUnit api:“超类的@BeforeClass方法将在当前类之前运行。”

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


1
投票

如何让你的@BeforeClass方法调用一个空的特定的BeforeClass()方法,这个方法可能被子类覆盖,也可能不被子类覆盖:

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

  protected void specificBeforeClass() {}
}

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

  // Tests
}

1
投票

可以使用dependsOnMethod

例如在春天的情况下(AbstractTestNGSpringContextTests

@BeforeClass(alwaysRun = true, dependsOnMethods = "springTestContextPrepareTestInstance")
© www.soinside.com 2019 - 2024. All rights reserved.