TDD 学习笔记 | 极客时间 | 徐昊·TDD 项目实战 70 讲
🏆 课程原文链接
🍿 源码地址
测试代码需要重构
- 重构生产代码的时候不要改测试代码
- 重构测试代码的时候不要改生产代码
随着功能迭代,测试代码也会冗余,需要及时重构,消除冗余代码
实际开发过程:
- 按功能写出出任务列表
- 先按照任务列表完成了一块功能点
- 发现了坏味道,开始重构
- 通过重构引入了新的组件,改变了架构
- 于是剩余的任务列表随之改变
- 陆续完成这些任务,发现不一致的测试策略,重组测试
任务列表
- 是随代码结构(重构)、测试策略(在哪个范围内测试)、代码实现情况(存在哪些缺陷)等因素而动态调整的列表
- 它的内容体现了我们最新的认知
- 它的变化记录了我们认知改变的过程
提前将 Option 对象提取出 flag 的代码在 bad path 翻车了
过早优化是万恶之源
—— 克努特优化原则,源于Donald Knuth的书《计算机编程艺术》(最早由Tony Hoare提出)
BooleanOptionParser.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // 徐昊老师的代码
public Object parse(List<String> arguments, Option option) {
int index = arguments.indexOf(flag);
if (!arguments.get(index + 1).startsWith("-")) {
throw new TooManyArgumentsException(option.value);
}
return index != -1;
}
// 我的代码
public Object parse(List<String> arguments, String flag) {
int index = arguments.indexOf(flag);
if (!arguments.get(index + 1).startsWith("-")) {
throw new TooManyArgumentsException("拿不到原始输入参数❗️🙀🙀🙀");
}
return index != -1;
}
|
视频中代码的坏味道
if 没有 “{}”
BooleanOptionParser.java
1
2
3
4
5
| public Object parse(List<String> arguments, Option option) {
int index = arguments.indexOf("-" + option.value());
if (!arguments.get(index + 1).startsWith("-")) throw new TooManyArgumentsException(option.value());
return index != -1;
}
|
C 语言伪代码
1
2
3
4
5
6
7
| if ((error = doSomething()) != 0)
goto fail;
goto fail;
if ((error= doMore()) != 0)
goto fail;
fail:
return error;
|
吞灭异常信息,无法追溯错误原因,导致排错困难
Args.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| public static <T> T parse(Class<T> optionsClass, String... args) {
Constructor<?> constructor = optionsClass.getDeclaredConstructors()[0];
try {
List<String> arguments = Arrays.stream(args).toList();
Object[] values = Arrays.stream(constructor.getParameters())
.map(it -> parseOption(arguments, it))
.toArray();
return (T) constructor.newInstance(values);
} catch (Exception e) {
// 此处视频中没有打印异常信息(吞灭了异常,无法追溯错误原因)
// 第一次遇到数组越界的问题时,如果不听视频中的介绍
// 从错误日志中只能看到测试结果不匹配的失败信息,无法定位错误原因
e.printStackTrace();
throw new RuntimeException();
}
}
|