制作测试数据

为了验证所写程序的正确性,需要使用记事本等纯文本编辑软件自制测试数据进行自我测试。为方便测试起见,一般自制的测试数据文件与可执行文件保存在于同一目录下,如图3.1所示。

图3.1

例如,某道题为求两数之和,题目名为sum,则可做N组输入测试数据sum1.in、sum2.in、sum3.in…再做与之相对应的标准答案文件sum1.ans、sum2.ans、sum3.ans…当然,必须保证自制的标准答案文件必须完全正确。例如sum1.in和sum2.ans的内容可与图3.2所示的相似。

图3.2

sum.cpp的代码内容可能如图3.3所示:

图3.3

程序中输入输出语句的格式必须严格匹配题目要求的输入输出文件格式。同理,为了验证程序是否正确,自制的若干组测试数据文件和答案文件,其测试数据也必须严格匹配题目要求,否则会发生读取错误。

注意测试数据文件的后缀名是否正确,特别是当操作系统默认设置为隐含文件后缀名时,完全文件名为sum.txt的文件,在屏幕上仅显示该文件名为sum,这往往导致在修改文件名时,看似将文件名修改成了sum.in,但实则该文件名为sum.in.txt。

现在的问题是,我写好了十多组测试数据,难道需要手工一个一个去测试吗?不会这么麻烦吧?

在平时的训练中,有现成的各类测试软件如Cena等,可以帮助我们自动测试程序的正确性。但是在正式比赛环境中,不可能给选手提供测试软件和正式测试数据,因此需要选手现场编写批处理文件和自制测试数据自我测试。例如有源程序名为sum.cpp,编译生成名为sum.exe的可执行文件。现有十组自制测试数据,输入数据文件分别为sum1.in、sum2.in、…sum10.in,输出答案文件分别为sum1.ans、sum2.ans、…sum10.ans,则可据此使用记事本等纯文本编辑软件(注意:不是Dev-C++),建立批处理文件如下所示:

1 @echo off
2 if  "%1" == "" goto loop
3 
4 copy sum%1.in sum.in > nul
5 echo Problem Test %1
6 
7 time/t
8 sum
9 time/t
10 
11 fc sum.out sum%1.ans
12 del sum.in
13 del sum.out
14 
15 pause
16 goto end
17 :loop
18 for %%i in (1 2 3 4 5 6 7 8 9 10) do call %0 %%i
19 :end

@echo off表示关闭输出结果显示。

if "%1"==""goto loop,其中%1为变量,在批处理文件运行时,将依次赋值为1,2,…,10。当批处理文件第一次运行时,由于%1为空值,所以将跳至第17行,即loop这一段。

copy a%1.in a.in>nul表示将某个输入文件(例如a1.in)拷贝复制为a.in。

echo Problem Test %1:在屏幕上显示echo后面的字符串,如“Problem Test 5”等,其中5为%1这个变量在当时的实际值。

time/t获取当前时间并输出到屏幕。

第8行即为运行已编译好的可执行文件a.exe。该可执行文件执行后,将从新生成的a.in中获取数据,最后将运行输出结果写入文件a.out中。

fc a.out a%1.ans为比较语句,即比较a.out与相应的答案文件是否有异同。

第12行和第13行删除a.in和a.out文件。

pause为暂停命令,当用户按回车键后,程序将继续运行。

for %%i in(1 2 3 4 5 6 7 8 9 10)do call %0 %%i表示批处理文件将运行十次,变量名将依次赋值为1,2,…,10。

该文件以后缀名.bat的形式例如test.bat保存在相同目录下,正确的批处理文件的图标应为两个啮合的齿轮,如图3.4所示。

图3.4

双击运行test.bat,程序将运行并自动测试每一组测试数据,如图3.5所示。

图3.5

根据实际测试,批处理文件中的比较命令对换行符不敏感,所以测试时注意最后的换行符陷阱。

程序的运行时间多少对于选手来说尤为重要,下例为获取程序运行时间的程序:

1 /*
2 程序名称: 获取程序运行时间
3 程序说明: 应用函数clock() 
4 */
5 #include <iostream>
6 using namespace std;
7 
8 int main()
9 {
10  clock_t time;        //如果仅仅判断该程序运行全部时间,则无须设time,
11  time=clock(); //在末行直接输出clock()的值即可
12  cout<<time<<endl;
13  Sleep(1000); //休眠1秒,Sleep首字母应大写
14  cout<<clock()-time<<"毫秒"<<endl;
15  system("pause");
16  return 0;
17 }

说明:此程序在某些版本的Dev-C++下无法运行,需加上Windows.h头文件。但要注意的是,Windows.h是无法在Linux平台上编译通过的,因此比赛时切勿使用此头文件。

另外,与自我测试不同的是,在正式比赛中,只允许选手提交程序的源文件,不允许提交自制的测试数据及可执行文件,且每个源文件分别保存在一个单独文件中。例如有选手考号为zj_123,所提交三道题的程序名分别为proble1、proble2、proble3,则一般提交的格式如图3.6所示。

图3.6