我有一个轻量级的测试框架,编写为JUnit Abstract测试。我想要做的是让实现子类定义他们的自定义测试类设置。我的计划是让抽象超类定义一个@BeforeClass
方法,该方法调用一个抽象的安装方法,每个子类都将被强制定义,但这会失败,因为@BeforeClass
方法必须是静态的,静态方法不能做成抽象也不能调用实例方法。
我可以假设子类将通过包含文档中所需的内容或抛出IllegalStateException
来进行设置,但我真的希望能够在接口级别强制执行此操作。原因。任何人都可以想到解决这个问题吗?
顺便说一句,我对使这些测试参数化有同样的问题(子类定义参数,但@Parameters
带注释的方法必须是静态的)。我通过运行第三方JUnitParams运行器来解决这个问题,该运行器允许使用方法级参数。请在此处查看:https://github.com/Pragmatists/JUnitParams
答案 0 :(得分:1)
对于您的主要问题,为什么不使您的父类抽象并使用@Before注释而不是@BeforeClass?例如:
public abstract class TestParent {
@Before
public void setup() {
doSetup();
}
protected abstract void doSetup();
// other stuff...
}
public class RealTest extends TestParent {
protected void doSetup() {
// custom setup
}
// custom tests...
}
这将强制子类重新定义doSetup()方法,而不使用静态方法。
答案 1 :(得分:1)
一个选项是让子类实现一个静态doSetupOnce()
方法,并从基类@BeforeClass
方法中反向查找和调用该方法。由于这需要是一个静态方法,因此只能在运行时强制执行它。
另一种方法是在基类中使用抽象doSetupOnce
实例方法,该方法在第一次调用父项@Before
方法时调用。这会在编译时强制执行该问题,但是实现者必须小心不要从此方法访问实例字段(因为这可能不是他们想要的)。
一般情况下(并且不知道您的具体情况),我不太喜欢这些方法中的任何一种,而是宁愿让实现者在需要时声明@BeforeClass
方法。将它们锁定在严格的基类方案中会导致比解决的问题更多的问题。还要考虑使用JUnit规则,这通常是比基类更好的选择(例如,因为它们是可组合的)。当然,您也可以将这两种方法结合起来,主要依赖于JUnit规则,另外还提供了一些带有预定义规则的基类,以方便使用。
答案 2 :(得分:1)
这可能超出范围或矫枉过正,但我认为值得一提,因为它们并没有那么不同。因此,我正在迈出一大步,建议您可以尝试TestNG,因为使用@BeforeClass注释的方法不一定是静态的,也不能用@Parameters注释。
您可以阅读2个框架here之间的差异,看起来他们也支持migrating JUnit tests to TestNG
答案 3 :(得分:1)
我认为不可能以干净的OO方式做到这一点。 @BeforeClass
不仅是一个静态方法,而且JUnit会在孩子的@BeforeClass
之前调用父级@BeforeClass
。
无论如何,你试图这样做必须暴露父类的内部静态,所以子类可以设置父类的字段,打破封装。
我认为最好的方法是使用@Before,但也有一个静态标志,如果之前已经调用了该方法,那么至少你可以短路并且只对第一次调用进行初始化。