Java 单元或集成测试可以有getter和setter吗?

Java 单元或集成测试可以有getter和setter吗?,java,unit-testing,junit,jboss-arquillian,Java,Unit Testing,Junit,Jboss Arquillian,我正在尝试编写集成测试,并希望在编程最佳实践、礼仪等方面以最佳方式进行测试 首先,我有一个关于如何在另一个测试类中重用现有测试的问题,我在主题中找到了 在将基本测试功能和相关成员字段移动到基类中之后,我发现我需要保护成员字段,或者我需要有它们相应的getter和setter,以便在继承的测试类中使用它们。以下是一个例子: public abstract class BaseTests { private Class classObj; // or protected with

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

首先,我有一个关于如何在另一个测试类中重用现有测试的问题,我在主题中找到了

在将基本测试功能和相关成员字段移动到基类中之后,我发现我需要保护成员字段,或者我需要有它们相应的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
  • 如果没有,是否有其他方法来实现示例中我想要的

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

共享对象会在单元测试中引起很多问题。大多数测试运行程序并行执行测试,并且不保证顺序执行。您的测试很可能会修改对象,因此共享对象可能会以不可预知的方式破坏其他测试

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

public ClassUnderTest GetNewClassUnderTest()
{
    return new ClassUnderTest("My favorite string", 1234);
}
至于将测试功能分解为助手方法,我不希望这样做。这使得测试代码很难快速扫描。如果它很简单,比如一两行代码,我总是在测试中内联使用它。如果可能的话,我开始考虑将我的测试重构成更简单的东西


编辑:我也强烈推荐阅读。这是一本很棒的书,其中有很多关于构建和构造单元测试的建议。

如果可能的话,我会在单元测试中完全避免状态。与其干扰属性,不如让派生测试重写一个工厂函数,该工厂函数生成测试所需的任何东西,并让通用测试调用该函数

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


如果这也行不通,那么使用
protected
setters似乎是下一个尝试的解决方案。或者重构您的测试,使上面的方法之一能够工作。

这是一个好的实践吗…

不,请参阅第二个答案

如果没有,是否有其他方法来实现示例中我想要的内容?

避免继承状态,并将helper方法重构为具有静态helper方法的类。i、 e

  • cunitesthelper.createTestCustomer()
  • CUnitteTheLPER.assertEqual(客户客户1、客户客户2)
JayFields()指出,编写单元测试时有不同的规则

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

换句话说:理想情况下,测试类或测试套件中的任何测试方法都是相互独立的。你只要读一种方法;你知道它在做什么;你看着失败;你找到了你需要的一切

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


但正如其他人所说:这在很大程度上取决于你和你的团队。为了创建真正有用的测试,您需要大量的经验;没有简单的规则可以保证在盲目遵循它们时取得好的结果。

这不是一个真正的getter,而是一个工厂。我称之为工厂方法。非常感谢您提供详细的答案。我也不喜欢将测试功能分解为助手方法,但如果我不这样做,我的测试方法可能会增长到数百行,原因是我的测试对象有太多需要设置的字段,并且测试还有一些子测试步骤,其中一些可能会用于其他测试。我也尝试遵循DRY原则:)这两个选项都没有什么大问题,字段可见性的标准规则适用于抽象测试类,就像任何其他类一样。起初,我想使用带有静态方法的helper(utility)类,但这也被认为是OOP方面的一个糟糕做法。