TDD测试驱动开发

Posted 赵jc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TDD测试驱动开发相关的知识,希望对你有一定的参考价值。

TDD测试驱动开发


本文是参照依着风睡_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;
        
    

测试全部通过

以上是关于TDD测试驱动开发的主要内容,如果未能解决你的问题,请参考以下文章

深度解读 - TDD(测试驱动开发)

深度解读 - TDD(测试驱动开发)

深度解读 - TDD(测试驱动开发)

深度解读 - TDD(测试驱动开发)

深度解读 - TDD(测试驱动开发)

深度解读 - TDD(测试驱动开发)