Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/ant/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 基本方法为私有时的单元测试包装方法_Java_Unit Testing_Tdd - Fatal编程技术网

Java 基本方法为私有时的单元测试包装方法

Java 基本方法为私有时的单元测试包装方法,java,unit-testing,tdd,Java,Unit Testing,Tdd,我读过关于单元测试包装器方法的文章。在以下代码中: public static Object methodA(Object arg) { if (arg == null) { return null; } else { return methodB(); } } 我不需要测试methodB()中的所有功能,只需测试arg为null的两种情况,而不是因为应该已经测试了methodB() 但是,如果methodB()是private方法,我应

我读过关于单元测试包装器方法的文章。在以下代码中:

public static Object methodA(Object arg) {
    if (arg == null) {
        return null;
    } else {
        return methodB();
    }
}
我不需要测试
methodB()
中的所有功能,只需测试
arg
为null的两种情况,而不是因为应该已经测试了
methodB()

但是,如果
methodB()
private方法,我应该测试
methodB()
将提供的所有功能,因为根据,private方法是实现细节

问题是,如果我有两个方法
methodA1()
methodA2()
,它们都像这样调用
methodB()

public static MyObject methodA1(int x) {
    MyObject obj = new MyObject();
    obj.setX(x);
    return methodB(obj);
}

public static MyObject methodA2(int y) {
    MyObject obj = new MyObject();
    obj.setY(y);
    return methodB(obj);
}

private static MyObject methodB(MyObject obj) {
    // doSomething with obj
    return obj;
}
我是否应该分别测试
methodA1()
methodA2()
?或者我可以测试私有方法
methodB()
,因为
methodA1()
methodA2()
只是
methodB()
的包装方法,所以如果
methodB()
测试正确,我就根本不需要测试
methodA1()
methodA2()

编辑:

起初,我为公共方法编写了单独的测试。但是问题是,如果
方法a
有很多变体,并且其中一些功能/需求是共享的,那么测试用例的代码将被复制。这就是为什么我想知道是否应该测试私有方法
methodB()

我遇到的真正问题是我需要在数据库中添加一条记录,并且我应该提供许多不同的API。例如,我应该提供:

MyObject addMale(String name, String job);     // fill sex with "Male"
MyObject addStudent(String name, String sex);  // fill job with "Student"
它们都检查参数是否有效,填充未指定的字段并调用private方法将记录实际插入数据库,这就是所谓的
methodB()

有很多这样的API,所以如果我只能在所有字段的情况下测试
methodB()
,也许我可以减少测试用例的重复,但是这样做单元测试是一种好的做法吗

编辑2:


我知道我可以测试私有方法,因为我在其他测试用例中使用了反射,我知道它也可以调用私有方法。但我的问题是在这种情况下,测试私有方法是否是一个合适的解决方案。

这实际上是一个我想了一段时间的问题,虽然它不一定正确,但我将分享我的观点

主要问题是私有方法很难测试。我做了一些谷歌搜索,有一些工具和技术可以让你访问私有方法(反射是我遇到的主要方法),但是它们看起来有点复杂

但是您编写私有方法的原因是因为有另一个方法,一个公共方法,调用它。因此,虽然不能直接测试私有方法,但可以通过测试调用它的公共方法来检查其功能


如果我是你,我会广泛地测试
methodA1()
methodA2()
,确保
methodB()
的所有功能都通过在公共方法上运行的测试进行测试。

你收到了一些关于为什么应该为
methodA1()
methodA2()编写单元测试的意见;你把他们推开了。你在这里问了这个问题;显然,您正在寻找一些不为它们编写完整单元测试的理由。让我们看看能否给你想要的答案。;-)

从您在编辑中添加的内容来看,您似乎在生成器模式上有一个变体。(例如)

我们如何测试构建器

由于生成器有4个属性,可以按任意顺序设置,因此将有4个!=24种不同的订单。完整的测试套件必须包括:

@Test public void testXYZW() { ... }
@Test public void testXYWZ() { ... }
// ... 21 more permutations ...
@Test public void testWZYX() { ... }
但就这些吗?不其中一些属性可能有默认值,因此我们还必须测试这些模式。总订单现在是P(4,4)+P(4,3)+P(4,2)+P(4,1)+P(4,0)=24+24+12+4+1=85单元测试

@Test public void testXWY() { ... }
@Test public void testWY() { ... }
@Test public void testZ() { ... }
// ... 61 more permutations ordering
这只测试X,Y,Z,W属性的每个排列,每个属性每个测试一个测试值。显然,为每一种可能的组合和排列编写一组详尽的测试是很不方便的

builder类的设计者会理解属性设置的排列不会影响结果的构造;为顺序排列编写测试实际上并没有增加测试覆盖率。对省略属性的测试很有用,因为它们测试默认值。再次测试省略属性的不同组合不会增加测试覆盖率。因此,经过仔细考虑,可能只需要两个测试:

@Test
public void testXYZW() {
    MyObject o = new Builder().setX(1).setY(2).setZ(3).setW(4).build();
    assertThat(o.wasBuiltProperly());
}

@Test void testDefaults() {
    MyObject o = new Builder().build();
    assertThat(o.wasBuiltProperlyFromDefaults());
}
如果正确,正在完成
methodB()
的完整测试,那么您可以安全地只测试
methodA1()
methodA2()
中输入的验证


通常,当一个私有方法被一个类中的多个方法使用时,它背后隐藏着一个独特的概念。它应该有自己的班级

它不应该在课堂外使用

有几种方法可以将
methodB
提取到它自己的类中,而不将其作为公共API的一部分提供:

  • 将它嵌套在使用它的类中,并给它一个受限范围

  • 将其放在较低级别的另一个模块中。使该模块可以从API中使用,但不能从客户端使用


如果
methodA1
做了与
methodA2
不同的事情,那么它显然需要单独测试。如果两种方法都做相同的事情,你只需要一个方法。稍微扩展一下:
methodA1
调用对象上的
setX
并将其传递给
methodB
,其中as
methodA2
调用对象上的
setY
,并将其传递给
methodB
。根据是否设置了对象的
X
,方法b的行为将有所不同,
@Test
public void testXYZW() {
    MyObject o = new Builder().setX(1).setY(2).setZ(3).setW(4).build();
    assertThat(o.wasBuiltProperly());
}

@Test void testDefaults() {
    MyObject o = new Builder().build();
    assertThat(o.wasBuiltProperlyFromDefaults());
}
@Test void testMethodA1Professor() {
    MyObject o = methodA1("professor");
    assertThat(o.wasBuiltProperlyWithProfessor());
}

@Test void testMethodA1WithNull() {
    MyObject o = methodA1(null);
    assertThat(o.wasBuiltProperlyWithNull());
}