我将从我的用例开始。我是一名教师,我有学生为我编写非常简单的 C++ 控制台程序。我想通过为他们的整个应用程序编写测试工具来自动对他们的程序进行评分。当他们使用 cin 要求输入时,我想给出它。当他们使用 cout 时,我希望能够解析他们的输出以获得正确的功能。我很确定我的老师在我上大学时为我们做了这件事。什么是解决这个问题的好方法?有没有比解析输出更好的方法来验证他们的代码?我应该解析他们的实际代码并寻找函数声明吗?谢谢。
4 回答
我建议您不要发明轮子并使用SPOJ Engine之类的东西,另请参阅它已经具有所有必要功能,例如:安全沙盒、提供伪造的用户输入等。
对了,我刚刚又想起了一件关于自动提交测试的事情
假设您要在 Linux 或 MacOS/X 等 POSIX-y 操作系统上执行此操作,forkpty() 将很容易做到这一点……请参阅下面的示例,该示例在子进程中运行“ping 127.0.0.1”并在读取()时打印出 ping 进程的 stdout 输出。您可以在同一个文件描述符上使用 write() 写入子进程的标准输入。
在 Windows 下也可以使用类似的技术,但按照传统,它在 Windows 下的难度和尴尬程度要高出 10 倍左右。让我知道这是否是您需要做的事情。
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#if defined(__linux__)
# include <pty.h> // for forkpty() on Linux
#else
# include <util.h> // for forkpty() on MacOS/X
#endif
int main(int argc, char ** argv)
{
int fd;
pid_t pid = forkpty(&fd, NULL, NULL, NULL);
if (pid > 0)
{
// We're running in the parent process. We can now write to the child process
// (and read from it) via (fd).
while(1)
{
char buf[4096];
int numBytesRead = read(fd, buf, sizeof(buf)-1);
if (numBytesRead > 0)
{
buf[numBytesRead] = '\0'; // ensure termination
printf("Read from child process's stdout: [%s]\n", buf);
}
else if (numBytesRead == 0)
{
printf("Child process exited\n");
break;
}
else {perror("read"); break;}
}
}
else if (pid == 0)
{
// We're running in the child process.
// Turn off the echo, we don't want to see that back on stdout
struct termios tios;
if (tcgetattr(STDIN_FILENO, &tios) >= 0)
{
tios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
tios.c_oflag &= ~(ONLCR); /* also turn off NL to CR/NL mapping on output */
(void) tcsetattr(STDIN_FILENO, TCSANOW, &tios);
}
char * const argv[] = {"/sbin/ping", "-c", "5", "127.0.0.1", NULL}; // Replace /sbin/ping with your favorite program to run instead
if (execvp(argv[0], argv) < 0) perror("execvp");
}
else if (pid < 0) perror("forkpty");
return 0;
}
这似乎是单元测试的一个很好的用途。编写一些标题,为标题定义的功能编写单元测试,然后将标题和单元测试提供给学生,并拒绝给他们的作业评分,直到测试通过。为了进一步减少浪费你的时间,让他们用-Wall -Werror
.
一旦测试通过,我会查看代码以确保它们没有做任何邪恶的事情只是为了让测试通过。
我见过的最好的 C++ 单元测试框架是Google Test。它易于编写且易于运行。
另一方面,如果您只关心输入和输出,只需使用 bash 和管道:
#!/bin/bash
for executable in * ; do
if cat input.txt | $executable | diff - expected-output.txt > /dev/null ; then
echo $executable passes
else
echo $executable fails
fi
done
您的问题相当开放,但您可能想要研究的一件事是 C++ 系统命令。在此处查看有关它的更多信息。