如果一个数能被3整除,那么返回结果Fizz,如果一个数能被5整除,返回Buzz。
如果两者同时满足,则输出FizzBuzz。
为了验证方法是否满足,我们在开发前设计了一组输入输出数据,测试代码也保留在了工程中。
初版业务简单,于是很快敲下代码。
public static String fizzBuzz(int num) {
if (num % 3 == 0 && num % 5 == 0) {
return "FizzBuzz";
} else if (num % 3 == 0) {
return "Fizz";
} else if (num % 5 == 0) {
return "Buzz";
} else {
return String.valueOf(num);
}
}
接着,业务变更。在保持以前的条件下,数字里面包含3,返回Fizz,包含5返回Buzz。因为怕程序员有误解,又多加了几个代表性的数据。
比如输入57,返回FizzBuzz,因为他满足3的倍数,又同时包含5。
看起来很简单,但为了通过小部分的测试,写了一堆if else来维护准确性,勉强完成任务。
这个过程中,不知不觉中完成了一次TDD。
说起TDD,可以追溯到二十多年前,他的全称是Test-Driven Development 测试驱动开发。可以理解成测试用例驱动开发,也有比较形象的理解:测试人员驱动开发人员。
各种软件工程中的技巧,首要目标就是为了解决复杂对象问题。TDD的思维呢,就是一种通过测试数据为导向的方案。
比如在维护旧系统的时候,经常会遇到“祖传代码”,“离职代码”等遗留代码,面对这种情况,TDD怎样帮助我们?
①阅读代码与相关文档,理解代码。
②追加测试用例。
③小步迭代,增量式改进。
用前言中的代码来说,用以上三步骤来改进。
首先,阅读理解,这是最让人厌烦的,在当下,可以尝试用AI去理解。
追加测试用例,重复性的工作,也可以交给腾讯云AI代码助手
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class FizzBuzzTest {
@Test
public void testFizzBuzz() {
assertEquals("FizzBuzz", FizzBuzz.fizzBuzz(15));
assertEquals("Fizz", FizzBuzz.fizzBuzz(3));
assertEquals("Buzz", FizzBuzz.fizzBuzz(5));
assertEquals("1", FizzBuzz.fizzBuzz(1));
assertEquals("2", FizzBuzz.fizzBuzz(2));
assertEquals("Fizz", FizzBuzz.fizzBuzz(6));
assertEquals("Buzz", FizzBuzz.fizzBuzz(10));
assertEquals("FizzBuzz", FizzBuzz.fizzBuzz(30));
assertEquals("4", FizzBuzz.fizzBuzz(4));
assertEquals("7", FizzBuzz.fizzBuzz(7));
}
}
小步迭代,其实就是重构这部分逻辑。
这是业务改进后,第一个代码的版本。
if ((String.valueOf(num).contains("3") || num % 3 == 0) && (String.valueOf(num).contains("5") || num % 5 == 0)) {
return "FizzBuzz";
} else if (String.valueOf(num).contains("3") || num % 3 == 0) {
return "Fizz";
} else if (String.valueOf(num).contains("5") || num % 5 == 0) {
return "Buzz";
} else {
return String.valueOf(num);
}
在以上没有进行任何注释的情况下,可读性很差。如何重构呢,先抓住其特征。
很多重复的判断,那就试着提取出来(Introduce Field 引入字段)
public static String fizzBuzz(int num) {
// 包含3
boolean containsThree = String.valueOf(num).contains("3");
// 整除3
boolean divisibleByThree = num % 3 == 0;
// 包含5
boolean containsFive = String.valueOf(num).contains("5");
// 整除5
boolean divisibleByFive = num % 5 == 0;
if ((containsThree || divisibleByThree) && (containsFive || divisibleByFive)) {
return "FizzBuzz";
} else if (containsThree || divisibleByThree) {
return "Fizz";
} else if (containsFive || divisibleByFive) {
return "Buzz";
} else {
return String.valueOf(num);
}
}
最后,代码完整的通过了测试用例。敏锐的你感觉似乎逻辑还可以再重构,刚想把字段提炼成函数,一个想法制止了你。
软件工程中没有银弹,TDD也只是一种方式的选择,它降低了“判断一个人是否理解了需求“的成本,降低了“发现当前架构愿景不容易实现的需求“的成本等。其中包含的一些手段,单元测试,重构放在任何地方都是有帮助的。
代码质量是一个笼统的词,以前,能稳定运行就是好代码,现在还要加上一条:经过测试的代码才是好代码!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。