【发布时间】:2013-02-27 07:37:07
【问题描述】:
我正在使用 mockito 进行练习,但对于如何测试依赖于本地对象中的方法调用的方法,我有点卡住了。 请参阅以下示例:
public class Worker {
public void work() {
Vodka vodka = new Vodka();
vodka.drink();
}
}
这个工人,不做他的工作,他喜欢喝酒。但是我想添加一个测试来证明他在工作时喝酒。但是没有办法这样做,因为我必须在调用方法 work 时验证方法 drink() 是否被调用。我想你同意我的观点,这是不可能测试的,所以我需要在开始测试之前打破依赖关系。 这是我的第一个疑问,您认为打破这种依赖的最佳方法是什么? 如果我只是将伏特加对象的范围更改为全局,我认为不会很好(我不想将它暴露给班级的其他部分)。我想过创建一个工厂,像这样:
public class Worker {
private VodkaFactory vodkaFactory = new VodkaFactory();
public void work() {
Vodka vodka = vodkaFactory.getVodka();
vodka.drink();
}
}
我不确定我是否正确地破坏了依赖关系,但我现在想做的是测试在执行 work() 时是否调用了方法 drink()。 我试过这个没有运气:
@Test
public void
does_the_worker_drink_while_working
() {
VodkaFactory vodkaFactory = mock(VodkaFactory.class);
Vodka vodka = mock(Vodka.class);
Worker worker = new Worker();
worker.work();
when(vodkaFactory.getVodka()).thenReturn(vodka);
verify(vodka,times(1)).drink();
}
我模拟工厂,何时会检测到工厂创建了一个新的伏特加对象。但是当我验证该方法调用了 1 次方法drink() 时,mockito 告诉我:
Wanted but not invoked:
vodka.drink();
-> at testing_void_methods_from_local_objects.WorkerSpecification.does_the_worker_drink_while_working(WorkerSpecification.java:22)
Actually, there were zero interactions with this mock.
我没有正确存根或者我做错了什么。你能帮我完成这个测试,并澄清一下测试这些无法测试的方法的最佳方法是什么?
我知道 mockito 有一个名为 doAnswer() 的方法,它用于模拟方法调用,你认为它在这种情况下有用吗? 我应该如何使用它?
更新:
我正在按照建议在 work() 之前调用 when(),并且我正在尝试允许从类外部设置工厂:
@Test
public void
does_the_worker_drink_while_working
() {
VodkaFactory vodkaFactory = mock(VodkaFactory.class);
Vodka vodka = mock(Vodka.class);
Worker worker = new Worker();
when(vodkaFactory.getVodka()).thenReturn(vodka);
worker.work();
verify(vodka,times(1)).drink();
}
现在这是生产代码:
public class Worker {
private VodkaFactory vodkaFactory;
public void work() {
Vodka vodka = vodkaFactory.getVodka();
vodka.drink();
}
public void setVodkaFactory(VodkaFactory vodkaFactory) {
this.vodkaFactory = vodkaFactory;
}
我得到的异常如下:
java.lang.NullPointerException
at testing_void_methods_called_from_local_objects.Worker.work(Worker.java:9)
这行写着vodka.drink()
抱歉,我仍然对问题所在感到困惑。
【问题讨论】:
-
正如你们中的一些人提到的,我做的第一件事是在
work()方法之前调用when。所以我在when(vodkaFactory.getVodka()).thenReturn(vodka);这一行向上移动了 1 行,我运行了测试,但它在vodka.drink();处出现空指针而失败,我有点不知道下一步该做什么。我不想将工厂包含在工人的构造函数中,我为什么要这样做? -
因为我记得看到你的另一个单元测试问题,我建议你买一本应该回答大多数常见问题的初学者书。对于这个特定的问题,请查看这个问题 - stackoverflow.com/questions/246038。您不必更改方法签名来测试它。相反,看看如果 Worker 喝了伏特加会发生什么可观察到的变化。我确定有一个。
-
谁说不能测试?您可以使用几种不同的模拟工具(PowerMock、JMockit)来为
work方法编写单元测试,而完全不改变它。您只需要模拟内部创建的Vodka对象,实际上,这两种工具都很容易做到。 -
@Rogerio 您能否提供一些示例来说明如何在不破坏依赖关系的情况下进行测试? PowerMock、JMock 和一些工具可能让你测试私有方法和硬依赖,但我认为这些方法并不总是可取的。我不同意你的看法。
-
@sfrj 我发布了一个带有示例测试的答案。为什么这样的事情是不可取的?我更喜欢它在被测代码中创建不必要的复杂性,例如
VodkaFactory类。
标签: java unit-testing tdd mockito legacy