2

我在 Java 中有一个类,它有一个用于计算一些默认值的私有方法;和两个构造函数,其中一个省略了该值并使用私有方法获取默认值。

public class C {
    private static HelperABC getDefaultABC() {
        return something; // this is a very complicated code
    }

    public C() {
        return C(getDefaultABC()); 
    }

    public C(HelperABC abc) {
        _abc = abc;
    }
}

现在,我正在尝试为这个类编写一个测试,并且想测试两个构造函数;第二个构造函数被传递默认值。

现在,如果getDefaultABC()是公开的,那将是微不足道的:

// We are inside class test_C
// Assume that test_obj_C() method correctly tests the object of class C
C obj1 = new C();
test_obj_C(obj1);

HelperABC abc = C.getDefaultABC();
C obj2 = new C(abc);
test_obj_C(obj2);

但是,由于getDefaultABC()是私有的,我不能从测试类中调用它!!!。

所以,我不得不写一些愚蠢的东西:

// Assume that test_obj_C() method correctly tests the object of class C
C obj1 = new C();
test_obj_C(obj1);

// here we will insert 20 lines of code
// that are fully copied and pasted from C.getDefaultABC()
//   - and if we ever change that method, the test breaks.
// In the end we end up with "HelperABC abc" variable
C obj2 = new C(abc);
test_obj_C(obj2);

除了简单地将方法从私有更改为公共之外,有没有办法解决这个难题(理想情况下,以某种方式将C.getDefaultABC()除类 test_C 之外的每个人都标记为私有)?

4

4 回答 4

4

Java 中没有等价的朋友。(上面来自 TI 的链接) 我这样做的方法是将方法声明为包保护,如下所示:

static HelperABC getDefaultABC()

这样做是允许您的测试代码调用getDefaultABC(),只要测试类在同一个包C中。当然,这也会让同一个包中的任何其他类也调用它,但我认为你将不得不忍受这个,这是你在不使用反射的情况下能做的最好的事情。但是如果你使用反射,其他每个类也可以使用反射来调用getDefaultABC(),所以它几乎是“脆弱的”。我只是让它受到包保护,所以至少它比使用反射更具可读性。


我将为您提供怀疑的好处,并说您可能继承了此代码,并且目前无法测试。你需要做的是尽你所能getDefaultABC()进入可测试的状态。测试甚至不必很好,你只需要一些信心。一旦你对你的测试有了信心,你就会发现其中的代码getDefaultABC()与获取默认的 ABC 毫无关系。较低级别的抽象,例如连接到数据库或其他任何东西。您需要识别该代码并将其提取到它自己的类中。然后,为提取的类编写更好的测试。

如果您将此代码重构为一个非常干净的状态,您应该能够摆脱不良测试并将其getDefaultABC()恢复到原来的private状态。 private意味着内部实现。您不应该直接测试内部实现。

于 2013-06-26T19:56:15.623 回答
2

不是绝对干净,但您可以使用反射在测试中调用私有方法。
对我来说,使用反射似乎更好,因为它是非侵入性的,您不必仅仅因为测试而更改方法访问修饰符。

像这样的东西:

    Method method = obj1.getClass().getMethod("getDefaultABC");
    method.setAccessible(true);
    HelperABC abc = (HelperABC) method.invoke(obj1);
于 2013-06-26T20:01:57.710 回答
1

使方法受到保护

protected static HelperABC getDefaultABC() {
        return something; // this is a very complicated code
    }

然后扩展测试类:

public class testC extends C{
   ...
}
于 2013-06-27T02:59:24.867 回答
0

如果您可以允许包级别访问,则通过对 SUT 和测试类位于同一包(不同的源文件夹)上的测试类遵循相同的包规则,恕我直言,您可以使其更干净。

于 2013-06-26T20:04:30.497 回答