本文是参照依着风睡_hcg博主的文章写的,[链接地址],如有错误的地方,欢迎大家讨论
链接地址
什么是测试驱动开发
测试驱动开发(Test-Driven Development),是敏捷开发中的一项核心实践和技术。 TDD是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么代码产品,之后再开始真正的业务需求开发。
测试驱动开发该怎么做?
我们只要记住三部曲就可以了,变红–>变绿–>重构,现在你可能还不理解这是什么意思,看完以下的文章就懂啦!
基于Junit的简单实操
在进行 TDD 案例编写的时候,看一个简单的需求(经典案例):
- 输入一个非元音字符,并预期返回字符本身 (输入"h" 返回“h”)
- 输入一个元音(a,e,i,o,u),返回 mommy (输入"a" 返回“mommy”)
- 输入一个元音超过字符串的30%,元音字母被 mommy 替换(输入"ab" 返回“mommyb”)
- 输入一个元音超过30%,并且存在连续元音的字符串,并预期只被替换一次(输入"aab" 返回“mommyab”)
如果直接进行代码编写,靠大脑分析分析整理代码的逻辑,和书写步骤的时候比较繁琐。 那么接下来就看下这个案例在 TDD 中如何逐步成型的吧。
需求一:输入一个非元音字符,并预期返回字符本身 (输入"h" 返回“h”)
- 第一步:首先编写测试用例代码,运行。结果变红
。(测试用例未通过)
@Test
public void test(){
String inputStr = "h";
String result = tddTest(inputStr);
Assert.assertEquals("h", result);
}
public String tddTest(String inputStr){
return null;
}
- 第二步:编写业务逻辑代码,运行。变绿
(测试用例通过)
public String tddTest(String inputStr){
return inputStr;
}
需求二:输入一个元音(a,e,i,o,u),返回 mommy (输入"a" 返回“mommy”)
第一步:加入新的业务逻辑(输入元音字母返回特定的字符串)运行。结果变红 (测试用例未通过)
@Test
public void test1(){
String inputStr = "h";
String result = tddTest(inputStr);
Assert.assertEquals("h", result);
}
@Test
public void test2(){
String inputStr = "a";
String result = tddTest(inputStr);
Assert.assertEquals("mommy", result);
}
public String tddTest(String inputStr){
return inputStr;
}
- 第二步:编写业务逻辑代码,运行。变绿
(测试用例通过)
public String tddTest(String inputStr){
List<String> list = Arrays.asList("a","e","i","o","u");
if(list.contains(inputStr)){
return "mommy";
}else{
return inputStr;
}
需求三:加入新的业务逻辑(元音字符超过字符串的 30% ,被特定字符串替换)运行结果变红
- 第一步:加入新的业务逻辑(元音字符超过字符串的 30% ,被特定字符串替换)运行。结果变红
(测试用例未通过)
@Test
public void test1() {
String inputStr = "h";
String result = tddTest(inputStr);
Assert.assertEquals("h", result);
}
@Test
public void test2() {
String inputStr = "a";
String result = tddTest(inputStr);
Assert.assertEquals("mommy", result);
}
@Test
public void test3() {
String inputStr = "ab";
String result = tddTest(inputStr);
Assert.assertEquals("mommyb", result);
}
- 第二步:编写业务逻辑代码,运行。变绿
(测试用例通过)
public String tddTest(String inputStr) {
List<String> list = Arrays.asList("a", "e", "i", "o", "u");
StringBuffer ret = new StringBuffer();
int count = 0;
for(int i = 0; i < inputStr.length(); i++) {
char ch = inputStr.charAt(i);
if(list.contains(ch + "")) {
count++;
}else{
continue;
}
}
if((float)count / (float)inputStr.length() > 0.3) {
for(int i = 0; i < inputStr.length(); i++) {
char ch = inputStr.charAt(i);
if(list.contains(ch + "")) {
ret.append("mommy");
}else{
ret.append(ch + "");
}
}
}else{
return inputStr;
}
return ret.toString();
}
- 第三步:检查是否需要重构,这个需求导致tddTest()函数的代码变得有点荣誉,所以需要进行代码的重构
计算元音在字符传中的数量,是一个独立的逻辑,可以进行方法抽取
private static int getYuanyinCount(List list, String inputStr) {
int count = 0;
for(int i = 0; i < inputStr.length(); i++) {
char ch = inputStr.charAt(i);
if(list.contains(ch + "")) {
count++;
}else{
continue;
}
}
return count;
}
也可以对元音替换方法进行抽取
private static String replace(List list, String inputStr) {
StringBuffer ret = new StringBuffer();
for(int i = 0; i < inputStr.length(); i++) {
char ch = inputStr.charAt(i);
if(list.contains(ch + "")) {
ret.append(REPLACE_CONSTANT);
}else{
ret.append(ch + "");
}
}
return ret.toString();
}
最后 : 对数字和字符串进行定义常量
{
private final static double VOWEL_PERCENT = 0.3;
private final static String REPLACE_CONSTANT = "mommy";
}
重构后的代码是以下代码:是不是看起来简洁了许多,而且也易于维护和拓展
private final static double VOWEL_PERCENT = 0.3;
private final static String REPLACE_CONSTANT = "mommy";
private static int getYuanyinCount(List list, String inputStr) {
int count = 0;
for(int i = 0; i < inputStr.length(); i++) {
char ch = inputStr.charAt(i);
if(list.contains(ch + "")) {
count++;
}else{
continue;
}
}
return count;
}
private static String replace(List list, String inputStr) {
StringBuffer ret = new StringBuffer();
for(int i = 0; i < inputStr.length(); i++) {
char ch = inputStr.charAt(i);
if(list.contains(ch + "")) {
ret.append(REPLACE_CONSTANT);
}else{
ret.append(ch + "");
}
}
return ret.toString();
}
public String tddTest(String inputStr) {
List<String> list = Arrays.asList("a", "e", "i", "o", "u");
int count = getYuanyinCount(list, inputStr);
if((float)count / (float)inputStr.length() > VOWEL_PERCENT) {
return replace(list, inputStr);
}else{
return inputStr;
}
}
需求四:加入新的业务逻辑(连续元音的字符串,并预期只被替换一次)运行结果变红
- 第一步:加入新的业务逻辑连续元音的字符串,并预期只被替换一次)运行。结果变红
(测试用例未通过)
@Test
public void test4() {
String inputStr = "aaabb";
String result = tddTest(inputStr);
Assert.assertEquals("mommyaabb", result);
}
第二步:修改业务逻辑,由于对元音替换我们前面已经进行了方法抽取,所以没必要在主方法中进行修改开发。变绿 (测试用例通过)
private static String replace(List list, String inputStr) {
StringBuffer ret = new StringBuffer();
int i = 0;
while(i < inputStr.length()) {
char ch = inputStr.charAt(i);
if(list.contains(ch + "")) {
ret.append(REPLACE_CONSTANT);
while(i < inputStr.length() - 1 && inputStr.charAt(i + 1) == ch) {
ret.append(ch + "");
i++;
}
}else{
ret.append(ch + "");
}
i++;
}
return ret.toString();
}
自此,开发基本完成,我又对多种情况的可能性,进尽可能的减少,行了进一步的修改和完善,使得 bug 数量以及后续的维护尽可能的减少。其中可能存在大量的不完美的代码和不健全的业务逻辑,如果读者有发现可以和我提出来,尽可能的改善。
完整代码
import org.junit.Assert;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
public class testDemo {
private final static double VOWEL_PERCENT = 0.3;
private final static String REPLACE_CONSTANT = "mommy";
@Test
public void test1() {
String inputStr = "h";
String result = tddTest(inputStr);
Assert.assertEquals("h", result);
}
@Test
public void test2() {
String inputStr = "a";
String result = tddTest(inputStr);
Assert.assertEquals("mommy", result);
}
@Test
public void test3() {
String inputStr = "ab";
String result = tddTest(inputStr);
Assert.assertEquals("mommyb", result);
}
@Test
public void test4() {
String inputStr = "aaabb";
String result = tddTest(inputStr);
Assert.assertEquals("mommyaabb", result);
}
private static int getYuanyinCount(List list, String inputStr) {
int count = 0;
for(int i = 0; i < inputStr.length(); i++) {
char ch = inputStr.charAt(i);
if(list.contains(ch + "")) {
count++;
}else{
continue;
}
}
return count;
}
private static String replace(List list, String inputStr) {
StringBuffer ret = new StringBuffer();
int i = 0;
while(i < inputStr.length()) {
char ch = inputStr.charAt(i);
if(list.contains(ch + "")) {
ret.append(REPLACE_CONSTANT);
while(i < inputStr.length() - 1 && inputStr.charAt(i + 1) == ch) {
ret.append(ch + "");
i++;
}
}else{
ret.append(ch + "");
}
i++;
}
return ret.toString();
}
public String tddTest(String inputStr) {
List<String> list = Arrays.asList("a", "e", "i", "o", "u");
int count = getYuanyinCount(list, inputStr);
if((float)count / (float)inputStr.length() > VOWEL_PERCENT) {
return replace(list, inputStr);
}else{
return inputStr;
}
}
}
测试全部通过
|