单位或整合测试可以有吸气剂和固定剂吗?

时间:2016-06-06 14:42:16

标签: java unit-testing junit jboss-arquillian

我正在尝试编写集成测试,并希望以最佳方式编写最佳实践,礼仪等。

首先,我有一个关于如何在另一个测试类中重用现有测试的问题,我在主题answer中找到了How to reuse existing JUnit tests in another test class?

在将基本测试功能和相关成员字段移动到基类之后,我发现我需要使成员字段受到保护,或者我需要有适当的getter和setter,以便我可以在继承的测试类中使用它们。这是一个例子:

public abstract class BaseTests {

    private Class classObj;      // or protected without getter/setter?

    protected void somethingHelper() {
        // Test something
    }

    protected void somethingElseHelper() {
        // Test something for classObj
    }

    public Class getClassObj() {
        return classObj;
    }

    public void setClassObj(Class other) {
        classObj = other;
    }
}

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

public class TestClass2 extends BaseTests {
    @Test
    public void testSomethingAndSomethingElse() {
        somethingHelper();

        ClassObj obj = new ClassObj();
        // set obj member fields
        // and then test something else
        setClassObj(obj);   // or classObj = obj;?
        somethingElseHelper();
    }
}

我的问题是:

  • 在基础测试类中使用成员字段并在继承的测试类中使用它们是一个好习惯吗?
  • 如果是,那更好的是:受保护的成员字段还是getter / setter?
  • 如果不是,还有另一种方法可以实现我想要的例子吗?

4 个答案:

答案 0 :(得分:5)

拥有getter并不一定是不好的做法,只要你记住单元测试是关于隔离行为和测试特定的工作单元。接下来,您应该确保您的getter总是返回对象的新实例,而不是将相同的副本发送到所有单元测试方法。

共享对象可能会导致单元测试中出现很多问题。大多数测试运行器并行执行测试,并不保证订单执行。您的测试很可能是修改对象,因此共享对象可能会以不可预测的方式破坏其他测试。

我经常创建小工厂方法来创建我在所有测试中使用的对象。特别是对于正在测试的特定类。

public ClassUnderTest GetNewClassUnderTest()
{
    return new ClassUnderTest("My favorite string", 1234);
}

至于将测试功能分解为辅助方法,我宁愿不这样做。它使测试代码很难快速扫描。如果它像一行或两行代码一样简单,我总是在测试中将其内联。除此之外,如果可能的话,我开始考虑将我的测试重构为更简单的事情。

编辑:我也强烈建议您阅读The Art of Unit Testing。这本书很棒,对构建和构建单元测试有很多很好的建议。

答案 1 :(得分:2)

Jay Fields(se-radio podcast)指出在编写单元测试时有不同的规则。

当然,您仍应尽量避免代码重复。但是,确定单元测试是否有用的主要因素是您需要多长时间才能理解失败的测试。

换句话说:理想情况下,测试类或套件中的任何测试方法都是相互独立的。你刚读了一个方法;你明白它在做什么;你看看失败;你发现了你所需要的一切。

将其与存在(复杂)耦合的解决方案进行比较;例如,因为你的具体测试方法依赖于很多来自该类的外部的东西;例如通过继承。

但正如其他人所说:这在很大程度上取决于你和你的团队。您需要很多经验才能创建真正有用的测试;盲目跟随它们并没有简单的规则可以保证很好的结果。

答案 2 :(得分:1)

如果可能的话,我会完全避免单元测试中的状态。派生测试覆盖了一个工厂函数,而不是弄乱属性,它会生成测试所需的任何东西,并具有该函数的通用测试调用。

如果无法避免属性,请考虑是否可以在构造函数中设置它们。然后,派生测试需要使用适当的值调用super构造函数。

如果这也不起作用,使用protected setter似乎是下一个尝试的解决方案。或者重构您的测试,以便上述方法之一可以正常工作。

答案 3 :(得分:0)

Is it good practice...

没有看到referenced question的第二个答案。

If no, is there another way to achieve what I wanted in example?

避免继承状态,并使用静态帮助器方法将辅助方法重构为类。即

  • CUnitTestHelper.createTestCustomer()
  • CUnitTestHelper.assertEqual(Customer customrer1, Customer customrer2)

这背后的原则称为Composition_over_inheritance