软件测试第二周作业 WordCount

时间:2022-12-03 06:17:50

github地址

https://github.com/Wangmmmm/WordCount

PSP2.1表格

PSP2.1 PSP 阶段 预估耗时 (分钟) 实际耗时 (分钟)
Planning 计划    
· Estimate · 估计这个任务需要多少时间 240 300
Development 开发    
· Analysis · 需求分析 (包括学习新技术) 30 30
· Design Spec · 生成设计文档 0 0
· Design Review · 设计复审 (和同事审核设计文档) 0 0
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 10 10
· Design · 具体设计 20 30
· Coding · 具体编码 150 200
· Code Review · 代码复审 20 20
· Test · 测试(自我测试,修改代码,提交修改) 5 50
Reporting 报告    
· Test Report · 测试报告 5 5
· Size Measurement · 计算工作量 5 5
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 20 20
  合计 265 340

解题思路

每一个计数功能都是一个子类,继承一个共同的父类,并统一输入输出的接口,在每一个类内部具体实现不同功能的统计。

对输入的字符串数组有一个专门的解析器进行解析,分析出需要多少种统计子类,以及输入文件列表,是否有停用词表,输出是否新定义输出文件等功能。

 

代码说明

//输入解析类

class  InputHandler  

 

//把停用词表的内容转化为字符串数组加载到内存中

private void SetStopList()  

 

//获取输出文件目录,如果没有-o参数,则设定为默认值

public String GetOutputFile()

 

//根据输入的参数,设置需要的统计类对象

public ArrayList<Statistics> GetStatMethods()

 

//将统计的结果格式化输出  filename:要读取的文件

public void BuildOutPutString(String inputfileName)

 

//根据输入的内容,返回一个需要读取的文件列表

public ArrayList<File> GetInputFile()

 

//递归调用的函数,循环查找所有文件夹下的文件

 void SetAllFile(File[] files,ArrayList<File> filelist,String format)

 

//所有统计方法的父类,规范接口

class Statistics

 

//统计方法的入口  c为当前从文件读取到的一个字符

public void  Stat(char c) 

 

//获取当前统计结果

public int GetCount()

 

//重置统计器,可以统计多个文件,多次使用

public void Reset()

 

//Statistics 的子类  专门用来统计单词的数量

class  WordStat 

 

//判断字符串是否在停用词表中

boolean Ignore(String s)

 

//判断当前读入的字符是否是有效的

boolean TestValid(char c)

 

//Statistics 的子类  专门用来统计字符的数量

 class CharacterStat

 

//Statistics的子类 专门用来统计行数 ,同时也是具体代码行,注释行,空行统计方法的父类。

class LineStat

 

//当前读入的行变量

 protected String currentLine;

 

//判断当前行有效字符的位置  beginIndex:从第几个字符开始计算

protected int GetValidPos(int beginIndex)

 

//判断是否是只有一个字符的行

protected boolean IsOnlyContainOneChar()

 

//判断是否只有一个字符的注释行

protected boolean IsOneSingleCharCommentLine()

 

//判断是否是只有注释的行

boolean IsOnlyContainComment()

 

//判断呢是否是代码行的类,继承自LineStat

class CodeLineStat

 

//判断是否是注释行的类,继承自LineStat

class CommentLineStat

 

//判断是否是空行的类,继承自LineStat

class NullLineStat

 

重要代码

解析输入参数的类 InputHandler

package Custom;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import StatMethod.*;
//输入解析类
public class InputHandler {
    String[] inputStrings;
    String defaltOutputFile="result.txt";
    
    
    
    public InputHandler(String[] s)
    {
        inputStrings =s;
        SetStopList();
    }
    //把停用词表的内容转化为字符串数组加载到内存中
    private void SetStopList()
    {
        WordStat.stopList=new ArrayList<String>();
        int index=StringsContain("-e");
        if(index==-1)return;
        if(inputStrings.length<=index+1)return;
        
        String fileName=inputStrings[index+1];
        
        WordStateIgnoreComma stater=new WordStateIgnoreComma();
        
        File file=new File(fileName);
           Reader reader = null;
             try {
               
                 // 一次读一个字符
                 reader = new InputStreamReader(new FileInputStream(file));
                 int tempchar;
                 while ((tempchar = reader.read()) != -1) {
                     // 对于windows下,\r\n这两个字符在一起时,表示一个换行。
                     // 但如果这两个字符分开显示时,会换两次行。
                     // 因此,屏蔽掉\r,或者屏蔽\n。否则,将会多出很多空行。
                     if (((char) tempchar) != '\r') {
                         
                         stater.Stat((char)tempchar);
                         
                     }
                 }
                 
                 WordStat.stopList=stater.GetString();
                 reader.close();
             } catch (Exception e) {
                 e.printStackTrace();
             }
        
        
    }
    
    //获取输出文件目录,如果没有-o参数,则设定为默认值
    public String GetOutputFile()
    {
        int index=StringsContain("-o");
        if(index==-1)return defaltOutputFile;
        
        if(inputStrings.length>(index+1))
        {
            return inputStrings[index+1];
        }
        
        return "";
    }
     boolean statC=false;
     boolean statW=false;
     boolean statL=false;
     boolean statA=false;
     ArrayList<Statistics> stats;
    //根据输入的参数,设置需要的统计类对象
    public ArrayList<Statistics> GetStatMethods()
    {
         stats=new ArrayList<Statistics>();
           if(StringsContain("-c")!=-1)
           {
               stats.add(new CharacterStat());
               statC=true;
               
           }
           if(StringsContain("-w")!=-1)
           {
               stats.add(new WordStat());
               statW=true;
           }
           if(StringsContain("-l")!=-1)
           {
               stats.add(new LineStat());
               statL=true;
           }
           if(StringsContain("-a")!=-1)
           {
               stats.add(new CodeLineStat());
               stats.add(new NullLineStat());
               stats.add(new CommentLineStat());
               statA=true;
           }
           return stats;
    }
 
    public String Print(String fileName)
    {
        String s="";
        
        int index=0;
        if(statC) {s+=(fileName+"," + stats.get(index).GetMethodName()+":"+stats.get(index++).GetCount()+"\r\n");}
        if(statW) {s+=(fileName+"," + stats.get(index).GetMethodName()+":"+stats.get(index++).GetCount()+"\r\n");}
        if(statL) {s+=(fileName+"," + stats.get(index).GetMethodName()+":"+stats.get(index++).GetCount()+"\r\n");}
        
        if(statA) {
                
            
                String  methodNames="代码行/空行/注释行:";
                String counts=String.valueOf(stats.get(index++).GetCount())+"/"+String.valueOf(stats.get(index++).GetCount())
                +"/"+String.valueOf(stats.get(index++).GetCount());
                s+=(fileName+","+methodNames+counts+"\r\n");
                
        }
        
        return s;
    }
    String outputMessage="";
    //将统计的结果格式化输出  filename:要读取的文件
    public void BuildOutPutString(String inputfileName)
    {
        
        outputMessage+=Print(inputfileName);
        for(int i=0;i<stats.size();i++)
        {
            stats.get(i).Reset();
        }
    }
    
    public String GetOutputMessage()
    {
        return outputMessage;
    }
    //根据输入的内容,返回一个需要读取的文件列表
     public ArrayList<File> GetInputFile()
    {
        int i=1;
        for(;i<inputStrings.length;i++)
        {
            if(!IsStatCommand(inputStrings[i]))
                break;
        }
        
        
        String filePath=inputStrings[i];
        String  absoluteFileRootPath="";
        if(filePath.contains(":"))
        {
            int index= filePath.lastIndexOf('\\');
            absoluteFileRootPath=filePath.substring(0, index);
            filePath=filePath.substring(index+1);
        }
        //System.out.println(absoluteFileRootPath+'\\'+filePath);
        
        File[]fileArray ;
        ArrayList<File> files=new ArrayList<File>();
        File rootFile;
        if(StringsContain("-s")!=-1)
        {
            String format=filePath.substring(filePath.indexOf('.'));
            if(absoluteFileRootPath=="")
            {
                rootFile=new File("./");
            }
            else {
                rootFile=new File(absoluteFileRootPath);
            }
            fileArray=rootFile.listFiles();
            if(fileArray.length==0)return null;
            
            SetAllFile(fileArray,files,format);
        }
        else 
        {
            if(absoluteFileRootPath=="")
            {
                files.add(new File(filePath));
            }
            else
            {
                files.add(new File(absoluteFileRootPath+'\\'+filePath));
            }
        }
        
        return files;
    }
//递归调用的函数,循环查找所有文件夹下的文件
     void SetAllFile(File[] files,ArrayList<File> filelist,String format)
     {
         if(files.length==0)return ;
         for(int j=0;j<files.length;j++)
            {
                
                if(files[j].getName().endsWith(format))
                {
                    filelist.add(files[j]);
                }
                else if(files[j].isDirectory())
                {
                    SetAllFile(files[j].listFiles(),filelist,format);
                }
            }
     }
     
     int StringsContain(String s)
        {
            for(int i=0;i<inputStrings.length;i++)
            {
                if(inputStrings[i].equals(s)){return i;}
            }
            return -1;
        }
     boolean IsStatCommand(String s)
     {
         if(s.equals("-s")||s.equals("-w")||s.equals("-c")||s.equals("-l")||s.equals("-a"))
         {
             return true;
         }
         return false;
     }
     boolean IsStopListCommand(String s)
     {
         if(s.equals("-e"))return true;
         return false;
     }
}

 

 所有统计功能的的父类 Statistics

  

package StatMethod;

public class Statistics {
    public int count=0;
    //public String methodName;
  
  //逐字符的输入读取的内容并分析
public void Stat(char c) { }
  //获取当前输入的统计结果
public int GetCount() { return count; } public String GetMethodName() { return null; }
  //重置统计器
public void Reset() { count=0; } }

 

以统计单词数的类举例 WordStat

package StatMethod;
import java.util.ArrayList;
public class WordStat extends Statistics {
  //输入统计的状态机
enum State{ Init, CountingChar, Skip }
  //停用词表
public static ArrayList<String> stopList; State state=State.Init; String currentString=""; //具体的重置函数 public void Reset() { state=State.Init; currentString=""; super.Reset(); } public void Stat(char c) { //if(c=='\r'||c=='\n')return ; //count++; switch(state) { case Init: { if(TestValid(c)) { count++; currentString+=c; state=State.CountingChar; } break; } case CountingChar: { if(TestValid(c)) { currentString+=c; break; } else { if(Ignore(currentString)) {count--;} currentString=""; state=State.Skip; break; } } case Skip: { if(TestValid(c)) { currentString+=c; count++; state=State.CountingChar; } break; } default: break; } //System.out.println(count); } public int GetCount() { if(Ignore(currentString))count--; currentString=""; return super.GetCount(); } boolean Ignore(String s) { //System.out.println("忽略测试的字符:"+s); for(int i=0;i<stopList.size();i++) { if (stopList.get(i).equals(s)) { return true; } } return false; } boolean TestValid(char c) { if(c==' '||c=='\r'||c=='\n'||c==','||c=='\t') { return false; } else { return true; } } public String GetMethodName() { return "单词数"; } }

 

测试设计过程

测试过程对于每一项功能单独测试,再进行组合测试,确保覆盖了所有可执行的代码,对文件名输入文件和文件夹也作出了测试,总共设计10个测试用例:

wc.exe
wc.exe -c wc.exe -c input.c wc.exe -c -w input1.c -o out1.txt wc.exe -c -w -l input2.c -o out2.txt wc.exe -c -w -l -a input3.c -o out3.txt
wc.exe -a -l -c -w input3.c -o out4.txt
wc.exe -s -c -w -l -a *.c -o out5.txt
wc.exe -c -w -l -a input3.c -e stoplist.txt -o out6.txt
wc.exe -s -c  -w -l -a  *.c -e stoplist.txt -o out7.txt

测试结果见项目下bin

result.txt  out1.txt  out2.txt  out3.txt  ou4.txt  out5.txt  out6.txt  out7.txt