如何在不同的测试环境中重用 JUnit 测试方法?



到目前为止,我一直在开发测试以支持我的项目中的某个应用程序。现在我已经启动并运行了一组测试,我需要为另一个类似的应用程序提供支持。在我的系统中,这两个应用程序的结果应该是相同的,因为它们都产生相同的操作,但来自不同的上下文。问题是,我正在寻找一种方法,可以重用我为第一个测试所做的测试,而无需为另一个测试用例复制它们的代码。

我目前正在Java EE 8下使用JUnit 4。

我的情况是这样的。给定如下测试:

class TestExample {
Context context;
@Before
public void setUp() {
context = new ContextA();
}
@After
public void terminate() {
context.dispose();
}
@Test
public void test1() {
context....
}
}
abstract class Context {
@Override
public void dispose() {
...
}
}
class ContextA extends Context {
}
class ContextB extends Context {
}

我希望能够对上下文A进行测试一次,然后对上下文B进行测试。

---o---

因此,在一段时间后回到这个问题之后,我从这个线程中收集了三个可能的问题解决方案:

  1. 参数
  2. 测试继承
  3. 上下文组合

但是,在实际测试用例上尝试了所有这些之后,我发现它们都不是完美的解决方案。它们确实解决了我在这个问题上提出的问题,但是当一个真实案例出现并且它们之间的上下文开始略有不同时,这些选项开始变得复杂和丑陋。

最后,我选择了最简单的解决方案:为每个不同的上下文复制测试源代码。它有效,但问题是随着时间的推移,维护测试变得越来越困难,因为对单个测试的更改必须复制到它的所有副本。

如何在不同的测试环境中重用 JUnit 测试方法?

通常,您不会

单元测试的一个核心点是:它们可以帮助您在以后对生产代码进行更改时快速识别错误。意思是:单元测试的主要要求是你能够快速阅读和理解它们。任何使这更困难的事情,比如避免代码重复的"复杂"解决方案都是有问题的。

从这个角度来看,测试代码的"规则"有时与生产代码的"规则"并不相同。在生产代码中,您希望(几乎(不惜一切代价避免代码重复。

然而,对于测试代码,有两个不同的测试类做非常相似的事情是完全可以的......两次。也许,只是也许您将公共代码提取到帮助程序方法(例如执行特定的复杂断言(到某些实用程序类中。

话虽如此,一个潜在的解决方案是:如果你真的想在多个"输入"上运行完全相同的测试,那么我建议你看看参数化测试。无需在代码中对context实例进行硬编码@Before,只需拥有多个不同的context对象,并为每个对象运行所有测试。

另一种方法是改进您的设计

在您的情况下,两者都为我们投射相同的基类。您可以通过将Context转换为普通类(删除abstract关键字(并将其移动到公共基础项目中来应用">偏爱组合而不是不规则"方法。这样,您就有了一个点来测试Context的行为。

您的专用类ContextAContextB将获得Context作为构造函数参数注入的实例,以便您可以在自己的测试中模拟它。

interface Context {
public void dispose();
}
class ContextImpl implements Context {
@Override
public void dispose() {
...
}
}
class ContextA implements Context {
private final Context common;
ContextA(@Inject Context common){
this.common = common;
@Override
public void dispose() {
common.dispose();
}
}
class ContextB implements Context {
private final Context common;
ContextB(@Inject Context common){
this.common = common;
@Override
public void dispose() {
common.dispose();
}
}

然后,验证(以及分别ContextAContextB的特殊行为(是否调用了传递的Context实例上的预期方法。

是的,您仍然有重复的测试,但它们非常简单,只要Context中的方法签名不更改,它们就永远不会更改。


有时,反过来做,并将专门的实现注入到持有共同行为的类中可能更好......

最新更新