我有一个抽象基类,我用它作为单元测试的基础(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) // <-/
不要把@BeforeClass
放在abstract
上。从每个子类中调用它。
abstract class A {
void doInitialization() {}
}
class B extends A {
@BeforeClass
void doSpecificInitialization() {
super.doInitialization();
}
@Test
void doTests() {}
}
看起来像TestNG有@BeforeClass(dependsOnMethods={"doInitialization"})
- 尝试一下。
检查您的import语句。它应该是
import org.testng.annotations.BeforeClass;
不
import org.junit.BeforeClass;
为什么不尝试在超类中创建一个抽象方法doSpecialInit(),从超类中的BeforeClass注释方法调用。
继承您的类的开发人员是否被迫实现此方法。
这里有另一个简单的解决方案。
我的特殊情况是我需要在执行超类中的“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
}
};
我希望这有帮助。这可以以“反向”顺序有效地执行静态设置。
我今天遇到了类似的问题,唯一的区别是Base类不是抽象的
这是我的情况
public class A {
@BeforeClass
private void doInitialization() {...}
}
public class B extends A {
@BeforeClass
private void doSpecificInitialization() {...}
@Test
public void doTests() {...}
}
发生了A类的@BeforeClass
方法从未被执行过。
使用隐私修饰符我发现,如果从类继承者看不到方法,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() {...}
}
结果发生以下情况:
这对我有用 -
abstract class A {
@BeforeClass
doInitialization() {...}
}
class B extends A {
@Override
@BeforeClass
doInitialization() {
//do class specific init
}
@Test
doTests() {...}
}
在我的情况下(JUnit)我在基类和派生类中使用相同的方法调用setup()。在这种情况下,只调用派生类的方法,并让它调用基类方法。
使用继承实现此更好,更清晰的方法可能如下 -
abstract class A {
@BeforeClass
void doInitialization() {}
}
class B extends A {
@Override
@BeforeClass
void doInitialization() {
super.doInitialization();
}
@Test
void doTests() {}
}
编辑:下面的答案适用于JUnit,但无论如何我都会留在这里,因为它可能会有所帮助。
根据JUnit api的说法:“超类的@BeforeClass方法将在当前类之前运行。”
我测试了这个,它似乎对我有用。
但是,正如@Odys在下面提到的那样,对于JUnit,您需要将两个方法命名为不同,否则将导致仅运行子类方法,因为父项将被镜像。
我将public
添加到抽象类中,TestNG(6.0.1)在doTests
之前执行了doInitialization()。如果我从A类中删除doInitialization()
,TestNG不会执行public
。
public abstract class A {
@BeforeClass
doInitialization() {...}
}
class B extends A {
@Test
doTests() {...}
}
我刚用5.11尝试了你的例子,我首先调用了基类的@BeforeClass。
你可以发布你的testng.xml文件吗?也许你在那里同时指定A和B,而只需要B。
随意关注testng-users邮件列表,我们可以仔细查看您的问题。
- 塞德里克
我刚刚完成了这个,并找到了另一种实现这一目标的方法。只需在抽象类中使用alwaysRun
或@BeforeClass
上的@BeforeMethod
,就像你期望的那样工作。
public class AbstractTestClass {
@BeforeClass(alwaysRun = true)
public void generalBeforeClass() {
// do stuff
specificBeforeClass();
}
}
当我运行时:JUnitCore.runClasses(TestClass.class);它将在子节点之前正确执行父节点(您不需要super.SetUpBeforeClass();)如果从Eclipse运行它:由于某种原因它无法运行基类。解决方法:显式调用基类:(BaseTest.setUpBeforeClass();)您可能希望在基类中有一个标志,以防您从应用程序运行它,以确定它是否已经设置。因此,如果您通过两种可能的方法运行它(例如从eclipse进行个人测试,通过ANT进行构建发布),它只会运行一次。
这似乎是Eclipse的一个错误,或者至少是意外的结果..
对于JUnit:正如@fortega所提到的:根据JUnit api:“超类的@BeforeClass方法将在当前类之前运行。”
但要注意不要将两个方法命名为同名。因为在这种情况下,父方法将隐藏父方法。 Source。
如何让你的@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
}
可以使用dependsOnMethod
。
例如在春天的情况下(AbstractTestNGSpringContextTests
)
@BeforeClass(alwaysRun = true, dependsOnMethods = "springTestContextPrepareTestInstance")