【问题标题】:How to reuse existing JUnit tests in another test class?如何在另一个测试类中重用现有的 JUnit 测试?
【发布时间】:2013-06-17 09:47:38
【问题描述】:

如何在另一个测试类中重用 JUnit 测试?

例如:

public TestClass1 {
    @Test
    public void testSomething(){...}
}

public TestClass2 {
    @Test
    public void testSomethingAndSomethingElse() {
        // Somehow execute testSomething()
        // and then test something else
    }
}

【问题讨论】:

  • 单元测试应该是独立的/隔离的。让一个测试依赖于另一个测试是个坏主意。
  • @Karna:用例:您的应用程序/框架支持多个数据库。所以你有一个基础测试类,其中包含所有功能的测试和每个数据库的一个扩​​展,用于创建连接、加载初始 DDL/数据等。
  • @AaronDigulla:这是个坏主意,有时坏是好事 :)

标签: java unit-testing junit


【解决方案1】:

一般来说,避免这种情况。它很容易使测试变得更加脆弱。如果TestClass1 失败,那么TestClass2 就会隐式失败,至少出于以下原因这是不可取的:

  • 代码被多次测试,浪费执行时间。
  • 测试不应相互依赖,它们应尽可能解耦
  • 如果这成为一种模式,则通过查看哪些测试失败(这是测试要点的一部分)来确定哪一部分代码被破坏将变得更加困难

偶尔共享测试代码部分很有用,尤其是对于集成测试。在不依赖测试本身的情况下,您可以这样做:

public abstract BaseTests {

    protected void somethingHelper() {
        // Test something
    }
}

public TestClass1 extends BaseTests {
    @Test
    public void testSomething(){
        somethingHelper();
    }
}

public TestClass2 extends BaseTests {
    @Test
    public void testSomethingAndSomethingElse() {
        somethingHelper();
        // and then test something else
    }
}

或者,您可以使用辅助类并完全避免继承。断言等可以放在somethingHelper() 方法中。

不要直接在TestClass2 中调用来自TestClass1 的方法。通过这种方式,测试用例的可读性会降低,并可能导致spaghetti frittata

【讨论】:

  • 您所说的对于单元测试用例来说是正确的。如果子场景依赖于父场景并且每个兄弟场景相互独立,那么集成或功能测试用例会怎样?
  • 这个问题被标记为“单元测试”,但对于集成或功能测试用例,我的答案的后半部分适用。可以为此目的共享测试代码部分。关键是避免直接从另一个测试调用一个测试,而是将共享代码移动到基类或助手中。这清楚地表明了测试套件的哪些部分是共享的。
  • 我正面临一个场景,我想确保特定的测试仍在运行和通过并且没有被删除(相关的开发代码更改是删除其中一些组件)你认为这是一个合法的场景,我可以调用现有的测试并确保它们仍然存在并且很好?否则,他们可能只是不小心删除了它们,而测试套件根本不会失败
【解决方案2】:

像往常一样,您可以:

  1. TestClass1 扩展TestClass2
  2. 使用委托从TestClass2 访问TestClass1

示例 1:

// Instantiate TestClass1 inside test method
public TestClass2 {
    public void testSomethingAndSomethingElse1() {
         new TestClass1().testSomething();
    }
}

示例 2:

// Instantiate TestClass1 as a member of TestClass2
public TestClass2 {
    private TestClass1 one = new TestClass1();
    public void testSomethingAndSomethingElse1() {
         one.testSomething();
    }
}

【讨论】:

    【解决方案3】:

    使用不同配置运行测试很常见。不要担心,继续前进。

    在第一步创建您自己的测试而不考虑任何配置:

    public abstract BaseTests {
        @Test
        protected void somethingHelper() {
            // Test something
        }
    }
    

    然后,扩展测试类并添加一些配置:

    public TestClass1 extends BaseTests {
        @Before
        public void setup(){
             // TODO: config
        }
    }
    

    不需要做具体的配置,但在可配置的系统中很常见(系统的主要功能必须对每个配置都有效)。

    在另一个测试用例中:

    public TestClass2 extends BaseTests {
        @Before
        public void setup(){
             // TODO: other config
        }
    }
    

    例如,可能有一个加密和解密过程,其中必须识别加密>解密的顺序。另一方面,当测试过程独特时,可以使用不同的算法。

    【讨论】:

      【解决方案4】:

      从逻辑上讲,没有理由从另一种测试方法中调用一种测试方法。运行一个测试的任何工具都可以轻松地执行包中的所有测试。但如果需要,您可以像在任何其他类中的任何其他方法一样调用它。

      您最可能想做的是为两种测试方法执行一些通用设置。您可以将that 代码放在公共类的实用方法中,并在两个测试中调用公共代码。

      【讨论】:

      • 用例:您的应用程序/框架支持多个数据库。所以你有一个基础测试类,其中包含所有功能的测试和每个创建连接的数据库的一个扩​​展,加载初始 DDL/数据。
      • 数据的预加载是一个设置步骤。它不应该是测试用例的一部分,而是所有测试用例的先决条件。
      • 这大约是我所说的 10%。测试用例将有很多很多测试用例,您需要为需要支持的每个数据库运行这些测试用例。复制这段代码没有意义。
      • 我从未说过需要复制测试用例。我的意思是这种关系应该不同于测试用例相互调用。您可以拥有不同的测试套件,它们使用相同的测试用例,每个测试用例具有不同的先决条件。否则建模就是错误的。
      • 我的例子是使用 OO 组织测试的完美例子。不需要测试套件、hack 或其他魔法。抽象基础测试有一个抽象的getConnection() 方法,其他的都是继承的。如果某个功能不支持某个数据库,您可以通过覆盖它轻松地排除它。
      猜你喜欢
      • 2011-01-30
      • 1970-01-01
      • 2020-09-19
      • 2021-12-27
      • 1970-01-01
      • 2019-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多