Java 单元测试和白盒测试

Java 单元测试和白盒测试,java,unit-testing,testing,Java,Unit Testing,Testing,目前,我正在为我完全了解的源代码编写单元测试(我想这意味着它被认为是白盒测试?)。所以,这不是测试驱动的开发 阅读本文()澄清了很多关于这一切的目的,但我仍然对我目前的立场感到困惑 假设我有这样一种方法: /* Some basic description on what doSomething() does */ public int doSomething(Var someVariable) { int someInteger = [code does a bunch of stuf

目前,我正在为我完全了解的源代码编写单元测试(我想这意味着它被认为是白盒测试?)。所以,这不是测试驱动的开发

阅读本文()澄清了很多关于这一切的目的,但我仍然对我目前的立场感到困惑

假设我有这样一种方法:

/* Some basic description on what doSomething() does */
public int doSomething(Var someVariable) {
    int someInteger = [code does a bunch of stuff to get this];
    someInteger = someOtherClassObject.doSomethingElse(someInteger);
    return someInteger;
}
现在,我真的不知道
doSomething()
应该做什么。文档还不足以真正告诉我基于
someVariable
的int应该是什么,而且我对源代码还不太熟悉,所以我自己也没有想到

但是我确实有实现,所以我看了一下这个方法,输入一些
Var
,然后按照代码并断言它将返回什么

public void testDoSomething() {
    ClassWithDoSomething object = new ClassWithDoSomething();
    assertEquals([what it looks like it would return], object.doSomething(new Var([some input would go here]));
}
在某种程度上,我模拟了doSomethingElse()调用和Var构造函数(以及其他外部类依赖项,如果需要的话)

我不知道这是否是进行这些单元测试的正确方法。我想我应该隔离这个方法,但我不知道我的断言在确定是否存在bug方面有多大意义,因为我只知道方法
doSomething()
在代码中应该做什么,以及它将如何进行,所以我写了我的断言来获得这个结果

我读过的答案详细说明了由于方法
doSomething()
的孤立故障,单元测试是如何受益的。但是,除了
doSomething()
的实现发生变化(这意味着单元测试的变化)之外,它的单元测试什么时候会失败呢

这是不是因为对源代码了解不够/源代码的文档化程度不够,无法知道应该得到什么输出

如果
[code做了很多事情来获得这个结果]
实际上只是
someVariable+3
其中someVariable是int,那么当我知道基于该实现的测试将要通过时,断言返回值是
someVariable+3
是否被认为是一个有意义的断言

但是它的单元测试什么时候会失败呢

你完全正确;当
doSomething
的实现发生更改时,单元测试将失败。单元测试的目的是在看似无害的更改实际上破坏了方法时捕获它

单元测试通常与您发布的代码片段相似:

public void testDoSomething() {
    ClassWithDoSomething object = new ClassWithDoSomething();
    object.someOtherClassObject = new MockOtherClass(); 
    assertEquals(4, object.doSomething(new Var("Input that maps to 4"));
}
SomeOtherClass
MockOtherClass
都实现了一个
IOtherClass
接口,该接口指定
doSomethingElse
MockOtherClass
在调用它的
doSomethingElse
方法时只返回输入。

但是它的单元测试什么时候会失败呢

你完全正确;当
doSomething
的实现发生更改时,单元测试将失败。单元测试的目的是在看似无害的更改实际上破坏了方法时捕获它

单元测试通常与您发布的代码片段相似:

public void testDoSomething() {
    ClassWithDoSomething object = new ClassWithDoSomething();
    object.someOtherClassObject = new MockOtherClass(); 
    assertEquals(4, object.doSomething(new Var("Input that maps to 4"));
}

SomeOtherClass
MockOtherClass
都实现了一个
IOtherClass
接口,该接口指定
doSomethingElse
MockOtherClass
在调用其
doSomethingElse
方法时只返回输入。

如果不知道代码的预期用途,那么编写单元测试是毫无意义的。 单元测试是检查给定的某些输入代码是否正确运行。如果您不知道“正确”是什么意思,那么如何测试它?在编写有价值的测试之前,您必须理解代码的意图

如果为了从头重写源代码而编写测试,情况就有点不同了。在这种情况下,测试是你能得到的最好的安全网,因为它们记录了实际行为,并保证它不会改变。但即使在这种情况下,在不知道代码的作用的情况下,也很容易忽略一些特殊情况


因此,我建议您在编写测试之前始终了解代码的意图。

如果您不知道代码的预期用途,那么编写单元测试是毫无意义的。 单元测试是检查给定的某些输入代码是否正确运行。如果您不知道“正确”是什么意思,那么如何测试它?在编写有价值的测试之前,您必须理解代码的意图

如果为了从头重写源代码而编写测试,情况就有点不同了。在这种情况下,测试是你能得到的最好的安全网,因为它们记录了实际行为,并保证它不会改变。但即使在这种情况下,在不知道代码的作用的情况下,也很容易忽略一些特殊情况


因此,我建议在编写测试之前始终了解代码的意图。

我认为这个问题更适合该站点。如果其他人同意,也许它可以被移植。这听起来很像你正在处理的代码从来没有被设计成可测试的。首先考虑使用副作用最少的方法和功能进行测试,然后在完成测试后再使用更大的方法和功能。因此在这种情况下,我将首先为
doSomethingElse
编写单元测试,然后再为
doSomething
编写任何单元测试,因为
doSomethingElse
的结果将取决于
doSomethingElse
。当测试
doSomething
时,我会模拟
doSomethingElse
的结果,您可以假设
doSomethingElse
在您使用测试
doSomething
的时间点上按预期工作。我是否接受代码不是真正设计为可测试的?因为我可以测试doSomethingElse()和doSomething(),就像你建议的那样(这就是我一直在做的)。只是我的断言将反映我在源代码中看到的结果。最终我不知道该怎么做