《有用的单元测试》 读书笔记

有效的测试

第4章 断言

  • 看见魔数的时候,或者!=== 这样的判断的时候,要考虑是否足够抽象,
  • 一个测试应该只有一个失败的原因,过度assert
  • 不要过度断言,任何一点小的改变都会使得测试失败
  • 不要在断言中使用位运算
  • 准备-执行-断言
  • 内敛数据或者逻辑,不要轻易使用外部数据文件
  • 不要使用魔数
  • 冗长的setup,可以封装到其他的private方法中

第5章 可维护性

  • 重复:语法重复和语义重复,使用参数化测试减少模版重复代码
  • 参数化测试,不能精准定位到到底是哪一组测试数据出了问题,需要在断言的失败消息中表明当前测试数据
  • 尽量避免条件逻辑,if、switch、while、for,
  • 因为网络、io、时间戳、随机数、多线程等导致测试不确定性失败
  • 使用Stream流代替File,因为File类是final的,不容易mock
  • 避免硬编码绝对路径,使用相对路径,将所有测试文件放到classpath下面,
  • 能不用物理文件就不用
  • 使用countdownlatch 代替Thread.sleep获取线程正确的结束时间,确保线程执行完

第6章 可信赖

  • 不要遗留注释掉的测试,要么重构,要么删除
  • 避免永不失败的测试,尝试使测试失败,expected,注意try-catch导致测试永远不抛出异常
  • 跟平台相关,可以使用assumeTrue,
  • 存在有条件的测试,可以将if换成断言

第7章 指南

  • 避免静态初始化,导致无法实例一个对象
  • 避免复杂的private方法,尝试短小的private方法,或者单独一个public方法或者一个类
  • 避免final方法,final是为了覆盖,以及内联带来性能优势,但是final方法不易测试,
  • 避免将可能会打桩的方法设置为static,比如产生随机数的方法
  • 在方法中,慎用new产生新的实例,这样导致测试很难覆盖该对象
  • 避免在构造函数中添加复杂的逻辑,确保构造函数中的代码,不会在单元测试中替换他们,可以将其抽取到子类容易覆盖的protected方法中
  • 避免单例,也可以单例的getinstance()方法,返回一个接口,而不是类接口更容易伪造
  • 降低代码重复时,多考虑使用组合,而不是继承

第9章 加速执行测试

  • 通过maven的几个插件,能够查看测试执行的时间和每个单元测试执行的时间,sufire,找到最慢的
  • countdownlatch替代sleep
  • 注意测试基类和setup、teardown方法中是否有大量的代码,仅仅只是针对某个测试,而其他测试用不到
  • 执行一个测试的顺序,
    • 找到所有父类和本类的@beforclass 方法,
    • 找到所有父类和本类的@before方法
    • 执行测试
    • 追踪父类以及本类的@after方法
    • 追踪父类以及本类的@afterclass方法
  • 当一个@befor中的方法只用被执行一次,可以考虑将其放到@beforclass
  • 保持本地运行,使用mock避免网络、io等
  • 最小化对数据库的访问
  • 考虑关闭日志,测试失败了之后,再开启执行一次
  • 如果cpu够用,可以考虑并行构建和并行测试
    • 并行构建
      • mvn -T {线程数} clean install
      • mvn -T 1C clean install
    • 并行测试
      • 在suefire插件中配置并行测试

junit

测试类
  • 测试方法必须是public void修饰,没有任何参数,并使用@Test注解
  • 测试方法的生命周期
    • 实例化测试类的一个实例
    • 调用父类以及当前类所有的setup
    • 执行测试方法
    • 调用父类以及当前类所有的teardown
  • setup和teardown可以在本类中定义,也可以在父类中定义
  • 多个setup和teardown都会被执行,但是不保证执行顺序
  • @beforclass 和 @afterclass针对测试类不是测试方法,每个测试类只会被执行一次
断言
  • 断言api org.junit.Assert
  • @Test(expected="异常")替代try-catch
  • 如果想要检查异常的信息,要回滚到try-catch
  • 使用try-catch要注意在try中最后调用fail(),防止不抛出异常测试通过
  • assertThat(someobj,matchthiscondition),matchthiscondition是Hamcrest匹配器,并且可以自定义实现Hamcrest的Matcher接口,
扩展junit
  • class-level注解@RunWith选择运行器,比如参数化测试@Runwith(Parameterized.class),通常默认runner在最后
  • 为单个测试方法配置超时@Test(timeout=x)
  • 为一个测试类中所有的方法配置超时,
@Rule
public MethodRule globalTimeout = new Timeout(20)
  • 除了@Test(expected=x),还以使用ExpectedException为单个方法甚至是测试类中的所有方法设置异常
@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void thispassed() {}

@Test
public void throwExpectedException() {
    thrown.expected(Exception.class);
}
  • 临时文件夹

@Rule
public TemporaryFolder folder = new TemporaryFolder();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值