WordCount编码和测试

WordCount编码和测试

项目地址:https://github.com/handsomesnail/WordCount

PSP表格

PSP2.1 PSP阶段 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 20 10
Estimate 估计任务需要多少时间 20 10
Development 开发 150 140
Analysis 需求分析 10 10
Design Spec 生成设计文档 10 0
Design Review 设计复审 10 0
Coding Standard 代码规范 10 0
Design 具体设计 20 20
Coding 具体编码 60 80
Code Review 代码复审 10 10
Test 测试 20 20
Reporting 报告 60 90
Test Report 测试报告 30 60
Size Measurement 计算工作量 20 20
Postmortem 总结 10 10
合计 230 240

解题思路

将问题分解为如下模块:

  • 解析命令行参数 (将输入转化为路径以及各种操作选项如-c -w -l等)
  • I/O操作 (将路径转化为相应路径下文件的字符串内容)
  • 字符串统计 (将各种操作选项抽象为各类处理字符串的方法)

程序设计实现

Program类
  • void Main(string[] args)
    Main函数作为程序入口
  • int Entrance(string[] args)
    测试入口, 返回值为错误码,正确执行返回0
  • string Read(string fileName)
    读取相对路径下名为fileName的文件并返回字符串
  • string Read(out string fileName)
    调用win32 api选取文件并读取返回字符串,同时返回选取的文件名
  • void Write(string fileName, string content)
    在相对路径下向名为fileName的文件追加内容为content的字符串
  • void LogArgumentError(int code)
    打印错误信息
  • int CountChar(string s)
    统计并返回字符串s的字符数
  • int CountWord(string s)
    统计并返回字符串s的单词数
  • int CountWord(string s,HashSet stopList)
    根据停用词表stopList统计并返回字符串s的单词数
  • int CountLine(string s)
    统计并返回字符串s的行数
  • void CountMoreAboutLine(string s, out int codeLineCount, out int emptyLineCount, out int commentLineCount)
    统计并返回行的详细信息(代码行/空行/注释行)
OpenFileName类

初始化打开或另存为对话框的信息,系统返回关于用户的选择信息到这个结构中

LocalDialog类
  • extern bool GetOpenFileName([In, Out] OpenFileName ofn)
    链接Comdlg32.dll中打开文件的系统函数

代码说明

/// <summary>统计字符数并打印</summary>
private static int CountChar(string s) {
    return s.Length; //直接返回字符串长度
}
/// <summary>统计单词数并打印</summary>
private static int CountWord(string s) {
    return CountWord(s, new HashSet<string>());
}
/// <summary>根据停用词表统计单词数并打印</summary>
private static int CountWord(string s,HashSet<string> stopList) {
    if (s.Length == 0)
        return 0;
    int count = 1;
    int i = -1;
    StringBuilder sb = new StringBuilder();
    foreach (char c in s) {
        i++;
        if (splitCharDic.Contains(c)) {
            if (i < s.Length - 1 && !splitCharDic.Contains(s[i + 1])) {
                if (!stopList.Contains(sb.ToString())) {
                    count++;
                    //Console.WriteLine(count + ":" + sb.ToString());
                    sb.Clear();
                }
                else {
                    sb.Clear();
                }
            }
        }
        else {
            sb.Append(c);
        }
    }
    return count;
}
/// <summary>统计行数并打印</summary>
private static int CountLine(string s) {
    int count = 0;
    //遍历直接统计'\n'数量
    foreach (char c in s) {
        if (count == 0) {
            count++;
            continue;
        }
        if (c == '\n') {
            count++;
        }
    }
    return count;
}
/// <summary>统计行的详细信息</summary>
private static void CountMoreAboutLine(string s, out int codeLineCount, out int emptyLineCount, out int commentLineCount) {
    codeLineCount = 0;//代码行
    emptyLineCount = 0;//空行
    commentLineCount = 0;//注释行
    int charInALine = 0; //当前行可见字符数
    int i = -1;
    CommentLineType CommentLine = CommentLineType.NonCommentLine;
    bool cancelCommentLine = false;
    foreach (char c in s) {
        i++;
        if (c == '\n'||i==s.Length-1) {
            if (CommentLine==CommentLineType.SingleCommentLine) {
                commentLineCount++;
                CommentLine = CommentLineType.NonCommentLine;
            }
            else if ((CommentLine == CommentLineType.SeveralCommentLine|| cancelCommentLine )&& charInALine<=1) {
                commentLineCount++;
            }
            else if (charInALine > 1) {
                codeLineCount++;
            }
            else emptyLineCount++;
            if (cancelCommentLine) {
                cancelCommentLine = false;
            }
            charInALine = 0;
        }
        if (charInALine <= 1 && c == '/' && i > 0 && s[i - 1] == '/') {
            CommentLine = CommentLineType.SingleCommentLine;
        }
        else if (c == '*' && i > 0 && s[i - 1] == '/') {
            CommentLine = CommentLineType.SeveralCommentLine;
        }
        else if (c == '/' && i > 0 && s[i - 1] == '*') {
            cancelCommentLine = true;
            CommentLine = CommentLineType.NonCommentLine;
        }
        else if (CommentLine == CommentLineType.NonCommentLine && !displayedCharDic.Contains(c)) {
            charInALine++;
        }
    }
}
/// <summary>通过图形界面读取文件 </summary>
public static string Read(out string fileName) {
    OpenFileName ofn = new OpenFileName();
    ofn.structSize = Marshal.SizeOf(ofn);
    ofn.file = new string(new char[256]);
    ofn.maxFile = ofn.file.Length;
    ofn.fileTitle = new string(new char[64]);
    ofn.maxFileTitle = ofn.fileTitle.Length;
    ofn.title = "选择文件";
    ofn.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000200 | 0x00000008;
    if (LocalDialog.GetOpenFileName(ofn)) {
        fileName = ofn.fileTitle;
        using (FileStream fs = new FileStream(ofn.file, FileMode.Open, FileAccess.Read)) {
            using (StreamReader sw = new StreamReader(fs, Encoding.UTF8)) {
                return sw.ReadToEnd();
            }
        }
    }
    throw new System.Exception("用户没有选择文件");
}

测试设计过程

  • 如何设计测试用例
    保证设计的测试用例应至少覆盖函数中所有的可执行语句
  • 哪些地方会导致程序高风险
    边界条件,未捕获的异常,未正确初始化的内存空间,空引用等等
  • 测试代码如何设计
    通过验证测试入口函数和相应分支的返回码覆盖代码的所有分支
namespace UnitTest {
    [TestClass]
    public class UnitTest1 {
        [TestMethod]
        public void TestMethod1() {
            string[] input = new string[] { };
            Assert.AreEqual(Program.Entrance(input), -1);
        }
        [TestMethod]
        public void TestMethod2() {
            string[] input = new string[] {"-q", "input.txt" };
            Assert.AreEqual(Program.Entrance(input), 2);
        }
        [TestMethod]
        public void TestMethod3() {
            string[] input = new string[] {"-c", "-c" ,"input.txt"};
            Assert.AreEqual(Program.Entrance(input), 1);
        }
        [TestMethod]
        public void TestMethod4() {
            string[] input = new string[] { "-c", "input.txt", "-a" };
            Assert.AreEqual(Program.Entrance(input), 7);
        }
        [TestMethod]
        public void TestMethod5() {
            string[] input = new string[] { "-c", "input.txt", "-o", "output.txt", "-c" };
            Assert.AreEqual(Program.Entrance(input), 4);
        }
        [TestMethod]
        public void TestMethod6() {
            string[] input = new string[] { "-c", "input.txt","-o" };
            Assert.AreEqual(Program.Entrance(input), 5);
        }
        [TestMethod]
        public void TestMethod7() {
            string[] input = new string[] { "-c", "-w", "-l" ,"example.txt" };
            Assert.AreEqual(Program.Entrance(input), 6);
        }
        [TestMethod]
        public void TestMethod8() {
            string[] input = new string[] { "-c", "-w", "-l", "input.txt" };
            Assert.AreEqual(Program.Entrance(input), 0);
        }
        [TestMethod]
        public void TestMethod9() {
            string[] input = new string[] { "-l", "-w", "-c", "input.txt", "-o" ,"output.txt"};
            Assert.AreEqual(Program.Entrance(input), 0);
        }
        [TestMethod]
        public void TestMethod10() {
            string[] input = new string[] { "-l", "-w", "-c", "-a", "input.txt", "-e", "stopList.txt", "-o", "output.txt" };
            Assert.AreEqual(Program.Entrance(input), 0);
        }
        [TestMethod]
        public void TestMethod11() {
            string[] input = new string[] { "-l", "-w", "-c", "-a", "-s", "*.txt", "-e", "stopList.txt" };
            Assert.AreEqual(Program.Entrance(input), 0);
        }
        [TestMethod]
        public void TestMethod12() {
            string[] input = new string[] { "-x" };
            Assert.AreEqual(Program.Entrance(input), 0);
        }

    }
}
  • 测试结果

参考文献链接:
[1]http://www.cnblogs.com/xinz/archive/2011/10/22/2220872.html
[2]http://www.cnblogs.com/xinz/p/5044037.html
[3]http://http😕/www.cnblogs.com/xinz/archive/2011/11/20/2255830.html

posted @ 2018-03-17 00:38  handsomesnail  阅读(350)  评论(2编辑  收藏  举报