7.3 在测试替身时使用Lambda表达式
编写单元测试的常用方式之一是使用测试替身描述系统中其他模块的期望行为。这种方式很有用,因为单元测试可以脱离其他模块来测试你的类或方法,测试替身让你能用单元测试来实现这种隔离。
测试替身也常被称为模拟,事实上测试存根和模拟都属于测试替身。区别是模拟可以验证代码的行为。读者若想了解更多有关这方面的信息,请阅读Martin Fowler的相关文章(http://martinfowler.com/articles/mocksArentStubs.html)。
测试代码时,使用Lambda表达式的最简单方式是实现轻量级的测试存根。如果交互的类本身就是一个函数接口,实现这样的存根就非常简单和自然。
在7.1.3节中,讨论过如何将通用的领域逻辑重构为一个countFeature方法,然后使用Lambda表达式实现不同的统计行为。例7-14展示了如何对此编写单元测试。
例7-14 使用Lambda表达式编写测试替身,传给countFeature方法
@Testpublic void canCountFeatures() {OrderDomain order = new OrderDomain(asList(newAlbum("Exile on Main St."),newAlbum("Beggars Banquet"),newAlbum("Aftermath"),newAlbum("Let it Bleed")));assertEquals(8, order.countFeature(album -> 2));}
对于countFeature方法的期望行为是为传入的专辑返回某个数值。这里传入4张专辑,测试存根中为每张专辑返回2,然后断言该方法返回8,即2×4。如果要向代码传入一个Lambda表达式,最好确保Lambda表达式也通过测试。
多数的测试替身都很复杂,使用Mockito这样的框架有助于更容易地产生测试替身。让我们考虑一种简单情形,为List生成测试替身。我们不想返回List本上的长度,而是返回另一个List的长度,为了模拟List的size方法,我们不想只给出答案,还想做一些操作,因此传入一个Lambda表达式,如例7-15所示。
例7-15 结合Mockito框架使用Lambda表达式
List<String> list = mock(List.class);when(list.size()).thenAnswer(inv -> otherList.size());assertEquals(3, list.size());
Mockito使用Answer接口允许用户提供其他行为,换句话说,这是我们的老朋友:代码即数据。之所以在这里能使用Lambda表达式,是因为Answer本身就是一个函数接口。
