1

问题描述

哟,写BUG呢!

clipboard.png

很有趣的一个表情包,描述了一个普通程序员的日常。

不管目前程序员主流的水平如何,至少我仍处在这个阶段。写出来的东西,总是有缺陷,总是考虑不周全。

在学习了软件测试这门课程之后,再去看代码,仿佛境界有所提升。

找缺陷

随机数

/**
 * 获取随机字符串
 * @param length 待获取的长度
 * @return 指定长度的随机字符串
 */
static String randomString(int length) {
    // 生成随机字符串
    StringBuilder sb = new StringBuilder( length );
    for( int i = 0; i < length; i++ )
        sb.append( source.charAt( random.nextInt(source.length()) ) );
    return sb.toString();
}
@Test
public void randomStringTest() {
    logger.debug("初始化长度");
    final int length = 20;

    logger.debug("获取随机字符串");
    String string = CommonService.randomString(length);

    logger.debug("断言");
    Assertions.assertThat(string.length()).isEqualTo(length);
}

一个普通的随机字符串程序,StackOverflow上找的,以及为这个方法配的单元测试。

看起来没什么毛病,注释齐全,缩进正确,空格也都有。

输入

至少,我们不会作到在自己的方法里写出个BUG来。BUG,往往都是我们未料及的输入产生的。

我们不能期望用户或别人调用我们方法时总是给我们传入合法的参数。

就拿刚才的代码来说,如果给个-1的长度会怎样呢?不妨一起来作一下。

clipboard.png

报错了,负的数组长度异常。

clipboard.png

完善

就像异常处理的规则一样,如果本级可以处理,那就在本级处理,如果不能处理,则给上级抛异常,让上级处理。

这里本级可以处理,你调用我的randomString方法,肯定是想获取随机字符串,既然非法,我就返回一个空字符串吧!

/**
 * 获取随机字符串
 * @param length 待获取的长度
 * @return 指定长度的随机字符串
 */
static String randomString(int length) {
    // 如果长度非正数,则返回空串
    if (length <= 0) {
        logger.error("传入了非法的长度参数");
        return "";
    }
    // 生成随机字符串
    StringBuilder sb = new StringBuilder( length );
    for( int i = 0; i < length; i++ )
        sb.append( source.charAt( random.nextInt(source.length()) ) );
    return sb.toString();
}
@Test
public void randomStringTest() {
    logger.debug("初始化长度");
    final int length1 = 20;
    final int length2 = -1;
    final int length3 = 0;

    logger.debug("获取随机字符串");
    String string1 = CommonService.randomString(length1);
    String string2 = CommonService.randomString(length2);
    String string3 = CommonService.randomString(length3);

    logger.debug("断言");
    Assertions.assertThat(string1.length()).isEqualTo(length1);
    Assertions.assertThat(string2.length()).isZero();
    Assertions.assertThat(string3.length()).isZero();
}

登录

登录方法:

@Override
public boolean login(User user) {
    logger.debug("获取相关用户");
    User persistUser = userRepository.findByUsername(user.getUsername());

    logger.debug("用户名不存在");
    if (null == persistUser) {
        return false;
    }

    logger.debug("用户名存在,密码不正确");
    if (!persistUser.getPassword().equals(user.getPassword())) {
        return false;
    }

    return true;
}

校验用户名和密码的登录方法,其实也是有可以完善的地方的。

clipboard.png

user上调用getUsername,如果传一个NULL进来,不就空指针异常了吗?

假设我们先不考虑前台的验证,我们就是要我们的api没毛病,先用notNull对数据进行校验。

clipboard.png

notNull方法会抛出IllegalArgumentException(非法参数异常),写个RestControllerAdviceExceptionHandler全局处理该异常,然后返回参数非法,加上该异常的提示信息。这就显得完美了。

clipboard.png

同样的可能造成空指针异常,在NULL上调用equals方法。

clipboard.png

为密码添加校验,保证持久化的User,其password都不为空!

总结

  1. 写方法时,一定要在该方法的最前面对所有的输入进行校验。
  2. 本级能推测出传入该参数的意图,可在本级中处理,不能推测,则抛出异常交给上级处理。
  3. 编码时勤思考,减少BUG产生的可能。

张喜硕
2.1k 声望423 粉丝

浅梦辄止,书墨未浓。