Java 如何对void函数进行单元测试?
现在我想测试Java 如何对void函数进行单元测试?,java,unit-testing,junit,Java,Unit Testing,Junit,现在我想测试perform方法。如何使用JUnit对该方法进行单元测试?要测试任何方法,必须通过更改任何变量的状态从方法的外部看到要测试的责任 通常通过从方法返回值来完成。但是如果没有这些,可以通过从方法范围之外修改某些内容,在许多方面完成,以防您在从方法返回某些内容时遇到任何“问题” 在您的情况下,您只记录一些消息。您的代码在某种意义上不是真正可测试的,因为它不会做与更改任何变量的状态直接相关的事情(因为您更改了变量以外的其他资源的状态,而您的代码无法直接访问该资源。您必须编写一些代码来读取该
perform
方法。如何使用JUnit对该方法进行单元测试?要测试任何方法,必须通过更改任何变量的状态从方法的外部看到要测试的责任
通常通过从方法返回值来完成。但是如果没有这些,可以通过从方法范围之外修改某些内容,在许多方面完成,以防您在从方法返回某些内容时遇到任何“问题”
在您的情况下,您只记录一些消息。您的代码在某种意义上不是真正可测试的,因为它不会做与更改任何变量的状态直接相关的事情(因为您更改了变量以外的其他资源的状态,而您的代码无法直接访问该资源。您必须编写一些代码来读取该外部资源的更改,因此使您的测试代码也依赖于读取。如果您在读取方面有问题,您的测试用例将无法通过,这与单元测试的精神。其主要思想是尽可能减少对外部代码或库的依赖)。但您的代码可以通过执行以下稍微重构/转移职责来进行测试:
class Elephant extends Animal {
public Elephant(String name) {
super(name);
}
void makeNoise() {
logger.info(" Elephant make Sound");
}
void perform(String day) {
if (day.equals("thursday") || day.equals("friday")) {
makeNoise();
}
}
}
String makeNoise() {
return "Elephant make Sound";
}
String perform(String day) {
if (day.equals("thursday") || day.equals("friday")) {
return makeNoise();
}
}
然后将记录从perform
方法返回的值的责任转移到使用它的责任上,如下所示:
class Elephant extends Animal {
public Elephant(String name) {
super(name);
}
void makeNoise() {
logger.info(" Elephant make Sound");
}
void perform(String day) {
if (day.equals("thursday") || day.equals("friday")) {
makeNoise();
}
}
}
String makeNoise() {
return "Elephant make Sound";
}
String perform(String day) {
if (day.equals("thursday") || day.equals("friday")) {
return makeNoise();
}
}
void()
函数更改程序的状态。这可以通过修改变量、文件、数据库等来完成
在您的情况下,您正在向记录器写入数据。如果这导致将“大象发出声音”写入文件,则您可以读取该文件,并查看文件中的数据是否包括您发出噪音的大象
但是,如果它不涉及任何您可以检查的内容(即:它只是在控制台上显示输出),那么您可能希望查看某种形式的依赖项注入(DI),您可以将输出设置为文件或其他易于阅读的内容
应该注意的是,您可以通过模拟对象并检查是否调用了适当的方法来绕过DI。Mockito Spy解决方案
阴性试验:
import org.junit.Test;
import static org.mockito.Mockito.*;
public class ElephantTest {
@Test
public void shouldMakeNoise() throws Exception {
//given
Elephant elephant = spy(new Elephant("foo"));
//when
elephant.perform("friday");
//then
verify(elephant).makeNoise();
}
}
或
依赖性
@Test
public void shouldDoNotMakeNoisesOnMonday() {
//given
Elephant elephant = spy(new Elephant("foo"));
//when
elephant.perform("monday");
then(elephant).should(never()).makeNoise();
}
了解
makeNoise
,以便计算调用次数。在测试中使用该类检查调用makeNoise
的次数是否正确
使用框架进行部分模拟
你基本上和上面做的一样,但不是手动编写MockElephant,而是使用一些模拟框架来创建它。这使得测试更简单,因为你需要更少的代码。而且它更容易阅读。但是如果发生奇怪的事情,它会让你更难理解正在发生的事情。如果是模拟框架,我认为它们是值得的
之所以称为部分模拟,是因为您只模拟类的一部分(本例中为单个方法)
另一种选择是使用普通mock,在您的情况下,这似乎是可行的(但在遗留代码中可能变得很困难)
在这里,您可以将记录器作为依赖项注入。例如,您可以创建一个额外的构造函数,允许您提供记录器。在测试中,您将使用模拟记录器,该记录器将再次计算其调用次数,可能还有它接收到的参数,并检查它是否具有预期值
同样,您可以使用模拟框架或普通的旧Java来实现这一点。logger来自哪里?可能来自
Animal
;)您需要一个模拟框架。谷歌。我会建议Mockito,但我可能有点偏颇,因为我与该产品有一些关联。我在动物类中使用的记录器,可以。我想使用junit测试,所以在我使用的地方,我想检查perform方法,确保它能在周四或周五为输入正确运行,那么我的junit测试用例中的代码是什么?您似乎在寻找一个我无法给出的确切代码答案。不仅因为我不想;也因为我不能:我不知道logger.info(string)
做什么。按照我在帖子中说的做:如果它写入文件,请读取您的文件。如果它写入控制台,则重定向输出。一旦你有了一个具体的方法来访问生成的状态数据,你就可以检查结果了。如果您添加了负面测试用例,其中大象在周一不会发出噪音,我会升级-并立即开始使用Mockito:)@ckonig我希望您已经在使用Mockito,附带负面测试用例;)
org.mockito:mockito-core:2.21.0