用于计算一系列角色的单词程序的软件测试

我做了一个程序,其中给出的输入应该是字符流,程序计算非空白字符和单词。 word被定义为由空白字符分隔的字符流。 所以这是程序..

#include  #include #include  #include int main(void) { unsigned long int wordcount = 0,charcount = 0, count=1; int ch; bool flag, prev; while ((ch = getchar()) != EOF) { if(isgraph(ch)) flag=true; else flag=false; if(flag) charcount++; if(count ==1) prev = flag; if(count != 1) { if(prev and (not flag)) wordcount++; prev = flag; } count++; } if((ch == EOF) and flag) wordcount++; printf("\nnumber of words counted are %lu \n", wordcount); printf("\nnumber of characters counted are %lu \n", charcount); return 0; } 

现在我用简单的句子检查了这个程序。 但仅仅是为了练习,我想对此进行详细的软件测试。 那我该怎么办呢? 我只是给出更多的句子吗? 我试图从项目古腾堡的一些小说中给出一些段落。 我还能在这做什么? 我也可以提高这个程序的效率吗?

有各种基本测试要做:

  1. 空的文件
  2. 文件只有一个空白
  3. 文件只有一个非空白
  4. 文件有一个空白和一个非空白
  5. 文件有一个非空白和一个空白
  6. 仅包含多个空白的文件
  7. 仅包含多个非空白的文件
  8. 文件有多个空格,后面是非空格

它继续……这是边界测试; 确保代码在边界条件下正常工作。

您将getchar()中的值赋值给unsigned long int (现在在问题中已修复)是​​不常见的。 由于常规字符的返回值为正,而对于文件结尾或错误,返回值为负(EOF),因此将其分配给有符号的普通int是正常的。

循环冗余后,你的测试ch == EOF ; 退出循环的唯一方法是条件为真。

使用和(宏)关键字not很常见。

最常见的是,人们不会将代码放在与块的开括号相同的行上。

你可以在你设置flag = true;if块中增加charcount flag = true; 。 您可以使用else块而不是if (count != 1) 。 事实上,AFAICT,你的代码:

 if(count ==1) prev = flag; if(count != 1) { if(prev and (not flag)) wordcount++; prev = flag; } 

可以写成:

 if (count > 1 and prev and (not flag)) wordcount++; prev = flag; 

描述’计算的字符数’并不严格准确; 它是您报告的图形(非空白,非控制)字符的数量。 尽管如此,这可能是在过度挑剔的结束时(同时观察到’单词数量’是一个单数量,它应该是’是’而不是’是’)。

count从1开始而不是零,这有点不寻常。 它似乎记录’比读入程序的原始字符数多一个’,这是一个不寻常的记录数量。 更常见的是,你也将它初始化为0,并修改我重写的测试:

 if (count != 0 and prev and (not flag)) 

(您可以使用count != 0count > 0 ;对于无符号值,这些术语是等效的。)

您可以通过适当地初始化prev (可能为false )来简化条件。

养成在左边测试常数的习惯,就像在

while(EOF!=(ch = getchar()))

…因为这会让你免于花费无数个小时,就在你最不能承受挫折时,当你意外地输入=当你的意思是==时。 由于您无法将变量分配给常量,编译器将标记您的错误,并保存您的对接。

根据我的经验,一旦你习惯了阅读这种代码,你就会发现找到正在测试的东西的速度要快得多,因为它位于if(旁边)(而不是在它的某个地方寻找它)如果您有一长串测试,例如打开文件,套接字等,然后通过malloc()分配内存来保存文件数据,则尤其如此。

PS:经过一番检查,有一些基本的CS 101事情值得一提……

1,这里有一个经典案例 – 在这种情况下,因为你需要在一个字符后面查看,即使在第一次通过while()循环时 – 用于播种while()循环。 解决方案是使用简单的if()块设置while()循环,该块执行与while()循环相同的逻辑。 (仅供参考,一段时间()是一组无限的if()s,具有终止条件)

正确的方法如图所示。 回报是能够抛出所有if()测试,并检查这是否是每次通过该循环的第一次通过while()循环。 这里的第一次传递由while()循环之前的if()测试处理。

2,我发现你的变量名称没有信息。 这并不意味着它们是“错误的”,但可能有人试图维护你的代码也会很困难。 根据我的经验,随着您更好地理解一段代码,变量名称变得越来越好。 使用它作为一个试金石测试你是否理解问题,有一个很好的解决方案,并知道原因。

3,当你发现自己将main()中的变量初始化为1时,它应该在你的脑海中提出一个关于正确流控制的标志,就像现在的PassKnt一样,被设置为1.另外,通常,你想增加一个循环结束时循环计数器/ if / while,而不是它的开头。 同样,这应该让你质疑你的逻辑。

注意:默认情况下,记事本以unicode格式保存。 如果使用记事本为此程序创建测试文件,请务必以ANSI格式保存。

我把它留在了,因为它使程序更容易理解,但这里不需要IsGraphFlg。 不是将IsGraphFlg分配给循环底部的WasGraphFlg,而是可以在if-else块的顶部和底部两半的底部完成,因为上下文提供与IsGraphFlag相同的信息。

  while (EOF != (ch = fgetc(pFile))) { if(isgraph(ch)) { IsGraphFlg=true; charcount++; } else { // this char is whitespace, last char was part of a word IsGraphFlg=false; if(WasGraphFlg) { wordcount++; } } WasGraphFlg = IsGraphFlg; PassKnt++; } 

您可能还注意到PassKnt现在也没有任何用途,也不再需要。

有人建议isgraph()是最佳的,但是当我创建一个bool数组并使用isgraph()对其进行初始化时,代码就会运行(从内存缓冲区中运行,这个数据的速度是此Dell XPS 8500上文件的10倍〜 )在不到2/3的时间内 – 9.25个时钟而不是每个字符14.75个。 这是一个完全可选的优化 – 虽然是一个重要的优化。

 bool IsGph[256]; for(i=0; i 

在使用中,if(isgraph(i))被主字符和字计数循环中的if(IsGph [i])替换。

代码已更新12/30/2012

 // Word_Counter.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "stdafx.h" #include  #include  #include  #include  #include  #define UCHAR unsigned char #define dbl double #define LLONG __int64 #define PROCESSOR_HZ ((LLONG) 3400000000) #pragma warning(disable : 4996) // // function prototypes FILE *OpenFiles (int *FileSz, char *FileName); // ----------------------------------------------------------------------- FILE *OpenFiles (int *FileSz, char *FileName) { FILE *pFile=NULL; if (NULL == (pFile = fopen ((char *)FileName, "r+t" ))) { printf ( "Can't open %s\n", FileName ); return NULL; } else { fseek(pFile,0,SEEK_END); *FileSz = ftell(pFile); rewind(pFile); printf("\nFile size is %i", *FileSz); return pFile; } } // ----------------------------------------------------------------------- int _tmain(int argc, char *argv[]) { bool IsGph[256]; UCHAR *p, *pBuff=NULL; int WrdKnt=0,CharKnt=0; int i, j, FileSz, LoopKnt=3500; time_t Etime=0,start=0, Eclocks=0; FILE *pFile=NULL; bool WasGraphFlg=false; // Initialize boolean array to detect printable characters for(i=0; i 

如果您的命令行参数指定文件名时出现问题,请在Visual Studio中的“项目 - >属性 - >配置属性 - >常规”下,将“Unicode”更改为严重错误的“多字节”字符集。 你总是可以在调试器中查看argv [1]的内存,找出argv []中的实际内容。