有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

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

我目前正在使用JavaEE8下的JUnit4

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

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 {
}

我希望能够为ContextA做一次测试,然后为ContextB做一次测试

---哦---

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

  1. 参数化
  2. 测试继承
  3. 语境构成

然而,在真实的测试用例上尝试了所有这些方法之后,我发现它们都不是完美的解决方案。它们确实解决了我在这个问题上提出的问题,但一旦一个真正的案例出现,它们之间的背景开始略有不同,那么这些选项就会变得复杂和丑陋

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


共 (2) 个答案

  1. # 1 楼答案

    另一种方法是改进你的设计:

    在你的例子中,两个项目都向我们展示了相同的基类。您可以通过将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中的方法签名不变,它们就永远不会改变


    有时候,反过来做可能更好,将专门的实现注入到包含公共行为的类中

  2. # 2 楼答案

    How do I reuse JUnit test methods for different testing contexts?

    通常情况下,您是而不是

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

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

    然而,对于测试代码来说,两个不同的测试类可以做非常相似的事情。。。两次。也许,只是也许你可以将普通代码提取到助手方法中(比如做一个特定的、复杂的断言)到一些实用程序类中

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