7.2 Lambda表达式的单元测试
单元测试是测试一段代码的行为是否符合预期的方式。
通常,在编写单元测试时,怎么在应用中调用该方法,就怎么在测试中调用。给定一些输入或测试替身,调用这些方法,然后验证结果是否和预期的行为一致。
Lambda表达式给单元测试带来了一些麻烦,Lambda表达式没有名字,无法直接在测试代码中调用。
你可以在测试代码中复制Lambda表达式来测试,但这种方式的副作用是测试的不是真正的实现。假设你修改了实现代码,测试仍然通过,而实现可能早已在做另一件事了。
解决该问题有两种方式。第一种是将Lambda表达式放入一个方法测试,这种方式要测那个方法,而不是Lambda表达式本身。例7-8是一个将一组字符串转换成大写的方法。
例7-8 将字符串转换为大写形式
public static List<String> allToUpperCase(List<String> words) {return words.stream().map(string -> string.toUpperCase()).collect(Collectors.<String>toList());}
在这段代码中,Lambda表达式唯一的作用就是调用一个Java方法。将该Lambda表达式单独测试是不值得的,它的行为太简单了。
如果换我来测试这段代码,我会将重点放在方法的行为上。比如例7-9测试了流中有多个单词的情况,它们都被转换成对应的大写。
例7-9 测试大写转换
@Testpublic void multipleWordsToUppercase() {List<String> input = Arrays.asList("a", "b", "hello");List<String> result = Testing.allToUpperCase(input);assertEquals(asList("A", "B", "HELLO"), result);}
有时候Lambda表达式实现了复杂的功能,它可能包含多个边界情况、使用了多个属性来计算一个非常重要的值。你非常想测试该段代码的行为,但它是一个Lambda表达式,无法引用。
作为例子,让我们来看一个比大写转换更复杂一点的方法。我们要把字符串的第一个字母转换成大写,其他部分保持不变。使用流和Lambda表达式,编写的代码形如例7-10所示。在➊处使用Lambda表达式做转换。
例7-10 将列表中元素的第一个字母转换成大写
public static List<String> elementFirstToUpperCaseLambdas(List<String> words) {return words.stream().map(value -> { ➊char firstChar = Character.toUpperCase(value.charAt(0));return firstChar + value.substring(1);}).collect(Collectors.<String>toList());}
如果要测试这段代码,我们必须创建一个列表,然后将想要测试的各种情况都测试到。例7-11展示了这种方式有多么繁琐,别担心,我们有办法!
例7-11 测试字符串包含两个字符的情况,第一个字母被转换为大写
@Testpublic void twoLetterStringConvertedToUppercaseLambdas() {List<String> input = Arrays.asList("ab");List<String> result = Testing.elementFirstToUpperCaseLambdas(input);assertEquals(asList("Ab"), result);}
别用Lambda表达式。我知道,在一本介绍如何使用Lambda表达式的书里,这个建议有点奇怪,但是方楔子钉不进圆孔。既然如此,大家一定会问如何测试代码,同时享有Lambda表达式带来的便利?
请用方法引用。任何Lambda表达式都能被改写为普通方法,然后使用方法引用直接引用。
例7-12将Lambda表达式重构为一个方法,然后在主程序中使用,主程序负责转换字符串。
例7-12 将首字母转换为大写,应用到所有列表元素
public static List<String> elementFirstToUppercase(List<String> words) {return words.stream().map(Testing::firstToUppercase).collect(Collectors.<String>toList());}public static String firstToUppercase(String value) { ➊char firstChar = Character.toUpperCase(value.charAt(0));return firstChar + value.substring(1);}
把处理字符串的的逻辑抽取成一个方法后,就可以测试该方法,把所有的边界情况都覆盖到。新的测试用例如例7-13所示。
例7-13 测试单独的方法
@Testpublic void twoLetterStringConvertedToUppercase() {String input = "ab";String result = Testing.firstToUppercase(input);assertEquals("Ab", result);}
