前言:本次测试过程中发现了几个未知字符,这里将其转化为十六进制码对其加以区分。
1)保存统计结果的Result文件中显示如图:
2)将其复制到eclipse环境下的切分方法StringTokenizer中却没有显示;
复制前:
复制后:
前后看似没有任何变化;
3)改动后的统计结果:
因此为了检测这个字符做了一个将其转化为十六进制码的小程序:
1 String t = "\0"; 2 String s = "\0"; 3 byte[] bbb = t.getBytes(); 4 int[] n = new int[bbb.length]; 5 for (int i = 0; i < n.length; i++) { 6 n[i] = bbb[i] & 0xff; //将每个字符的十六进制码保存到数组中 7 } 8 for (int j = 0; j < n.length; j++) { 9 System.out.println(Integer.toString(n[j], 0x10)); 10 } 11 System.out.println("-----------------"); 12 byte[] b = s.getBytes(); 13 int[] in = new int[b.length]; 14 for (int i = 0; i < in.length; i++) { 15 in[i] = b[i] & 0xff; 16 } 17 for (int j = 0; j < in.length; j++) { 18 System.out.println(Integer.toString(in[j], 0x10)); 19 }
运行结果如下:
从结果可以看出,这个未知字符是由三个字符组成,而类似的难以识别的字符还有很多。
此外,在做单元测试之前还做了一项额外的测试——read()方法读取文件时单次读取的字符数量对效率的影响:
选取了从1-128、129-256、257-384、385-512四个范围,分别进行了测试。
总测试次数2560次,耗时10min左右,统计结果:
当取值在200左右时运行速率最快,平均值在210ms左右.
单元测试
对Java工程进行的单元测试,使用的工具为Eclipse集成的Juint4。
1.对FileProccessing类进行测试,测试其输出到控制台与输出到文件的结果与预期是否相同。Juint代码如下:
输出到控制台:这里用到了重定向输出,将要输出到控制台的字符串输出到缓冲区,并与预期结果进行比对。
1 @Test 2 public void testFP() throws Exception { 3 4 final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); 5 System.setOut(new PrintStream(outContent)); //重定向输出,方便后面进行比对 6 new FileProccessing("content.txt", 200); 7 assertEquals( 8 "~~~~~~~~~~~~~~~~~~~~\r\ncontent\r\ntotals of the words:6\r\nquantity of vocabulary:5\r\nvery——2\r\nenglish——1\r\nis——1\r\nmy——1\r\npoor——1\r\n~~~~~~~~~~~~~~~~~~~~\r\n", 9 outContent.toString()); 10 11 }
输出到文件:生成实例后分别建立两个文件流,一个读取实际结果文件,一个读取预期结果文件,通过循环逐行比对。
1 public void testFPtoFile() throws Exception{ 2 new FileProccessing("E:\\Test3\\Test1.txt"); //测试文件 3 FileReader expect = new FileReader("E:\\Test3\\Expect.txt"); //用来保存期待的结果 4 BufferedReader ep= new BufferedReader(expect); 5 FileReader actual = new FileReader("Result.txt"); //实际的结果文件 6 BufferedReader at = new BufferedReader(actual); 7 String temp; 8 while((temp = at.readLine()) != null){ 9 assertEquals(ep.readLine(),temp); //对文件中内容逐行比较 10 } 11 at.close(); 12 actual.close(); 13 ep.close(); 14 expect.close(); 15 }
用例截图:
单元测试结果:
代码覆盖率:覆盖率为72%,未覆盖到的部分为主函数中为用户提供输入的代码段。
2.对于上面的测试用例进行改进,对main()函数不同情况的的输入输出进行测试。Juint代码如下,大致分为四种情况:
1>由命令行传入参数:
1 @Test 2 public void testMain1() throws Exception { 3 String[] test = { "E:\\Test3\\Test1.txt" }; 4 WordFrequencyCount.main(test); //生成实例 5 6 FileReader expect = new FileReader("E:\\Test\\Expect.txt"); 7 BufferedReader ep = new BufferedReader(expect); 8 FileReader actual = new FileReader("Result.txt"); 9 BufferedReader at = new BufferedReader(actual); 10 11 String temp; 12 while ((temp = at.readLine()) != null) { 13 assertEquals(ep.readLine(), temp); 14 } 15 16 at.close(); 17 actual.close(); 18 ep.close(); 19 expect.close(); 20 }
2>传入参数为文件夹时:
1 @Test 2 public void testMain2() throws Exception { 3 String[] test = { "E:\\Test3" }; //文件夹中内容为Test1.txt 4 WordFrequencyCount.main(test); 5 6 FileReader expect = new FileReader("E:\\Test\\Expect.txt"); 7 BufferedReader ep = new BufferedReader(expect); 8 FileReader actual = new FileReader("Result.txt"); 9 BufferedReader at = new BufferedReader(actual); 10 11 String temp; 12 while ((temp = at.readLine()) != null) { 13 assertEquals(ep.readLine(), temp); 14 } 15 16 at.close(); 17 actual.close(); 18 ep.close(); 19 expect.close(); 20 21 }
3>由控制台重定向输入:这里运用了重定向输入,并且将String转化为输入流。
1 @Test 2 public void testMain3() throws Exception { 3 String[] test = {}; 4 String str = "< E:\\Test3\\Test1.txt\n"; 5 ByteArrayInputStream instr = new ByteArrayInputStream(str.getBytes()); //将String转化为输入流 6 7 System.setIn(instr); //重定向输入 8 WordFrequencyCount.main(test); 9 10 FileReader expect = new FileReader("E:\\Test\\Expect.txt"); 11 BufferedReader ep = new BufferedReader(expect); 12 FileReader actual = new FileReader("Result.txt"); 13 BufferedReader at = new BufferedReader(actual); 14 15 String temp; 16 while ((temp = at.readLine()) != null) { 17 assertEquals(ep.readLine(), temp); 18 } 19 20 at.close(); 21 actual.close(); 22 ep.close(); 23 expect.close(); 24 }
4>由控制台输入文件名及内容:这一部分使用了重定向输入和输出;由于main()函数中为了方便用户使用,会有输出作为引导,因此在比对时要把这部分输出也纳入考虑。
1 @Test 2 public void testMain4() throws Exception { 3 String[] test = {}; 4 String str = "content\nMy English is very very poor.\n"; 5 ByteArrayInputStream instr = new ByteArrayInputStream(str.getBytes()); 6 7 System.setIn(instr); 8 9 final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); 10 System.setOut(new PrintStream(outContent)); 11 WordFrequencyCount.main(test); 12 assertEquals( 13 "请输入文件名:\r\n请输入内容,结尾以回车后ctrl+z结束:\r\n~~~~~~~~~~~~~~~~~~~~\r\ncontent\r\ntotals of the words:6\r\nquantity of vocabulary:5\r\nvery——2\r\nenglish——1\r\nis——1\r\nmy——1\r\npoor——1\r\n~~~~~~~~~~~~~~~~~~~~\r\ntime:1ms\r\n", 14 outContent.toString()); 15 } //要考虑到main()函数中面向用户的输出
(为了方便测试,这一部分用例与之前相同,这里不再展示)
单元测试结果:
代码覆盖率:覆盖率为94%,加入了对于面向用户的输入输出的测试。仍有未覆盖到的代码,主要是抛出异常、异常处理、异常检测部分的代码。
通过此次单元测试了解到:System.out.println()与System.out.print()方法差别不仅仅在于行末多了换行符\n,而是\r\n。同时通过这次单元测试发现了原程序中的bug:用read()方法读取文件时用来保存结果的char[]不会自动清空,而是以覆盖的方式读取字符,因此会导致统计结果有误。
代码地址:
HTTPS https://coding.net/u/regretless/p/WordFrequencyCount/git
SSH [email protected]:regretless/WordFrequencyCount.git
GIT git://git.coding.net/regretless/WordFrequencyCount.git