我是一名计算机科学专业的学生,刚接触 C,正在尝试为此程序编写单元测试:
Board *get_board_sizes() {
int row_count, column_count, mine_count = 0;
Board *struct_to_return = (Board *)calloc(1, sizeof(Board));
int rerun = 0;
do {
if (rerun == 1) {
printf("Incorrect size");
}
rerun = 1;
printf("Choose how many rows, columns, and mines you would like\n");
printf("Note that maximum number of rows anc columns are 30 and maximum number of mines are rows*columns\n");
scanf("%d %d %d", &row_count, &column_count, &mine_count);
while (getchar() != '\n');
} while ((row_count > 30 || row_count < 1) || (column_count > 30 || column_count < 1) || (mine_count < 1 || mine_count >= (row_count * column_count)));
//while(getchar() != '\n');
struct_to_return->row_count = row_count;
struct_to_return->column_count = column_count;
struct_to_return->mine_count = mine_count;
return struct_to_return;
}
我的问题是有什么方法可以测试
scanf
功能吗?我的想法是我可以将它应该扫描的数字保存到一个文件中并尝试从那里获取它,但我正在努力将它放入单元测试中。
我想这样做:
TEST get_fitting_number_from_players() {
char file[] = "tests/board_size/fitting_number";
FILE *fp = fopen(file, "r");
Board *size = get_board_sizes(fp);
ASSERT(/*havent added yet*/);
}
但是我没有看到 get_board_sizes 函数能够从文件中获取数字。有什么办法吗?
对
get_board_sizes
函数进行单元测试的一种方法是修改函数,使其采用提供输入的附加参数,而不是将其硬编码为从 stdin 读取。像这样的东西:
Board *get_board_sizes(FILE *in) {
/* ... */
fscanf(in, "%d %d %d", &row_count, &column_count, &mine_count);
/* ... */
}
然后在您的单元测试中,您可以合成该功能的输入。使用cgreen进行单元测试,我写了下面的测试。在这段代码中:
get_board_sizes
函数的输入。get_board_sizes
Ensure(GetBoard, parse_input) {
char tempname[20];
int fd;
FILE *test_stdin;
Board *board;
sprintf(tempname, "stdinXXXXXX");
fd = mkstemp(tempname);
unlink(tempname);
assert_that(fd, is_greater_than(-1));
test_stdin = fdopen(fd, "r+");
assert_that(test_stdin, is_not_null);
fputs("10 15 5\n", test_stdin);
fseek(test_stdin, 0, SEEK_SET);
board = get_board_sizes(test_stdin);
assert_that(board->row_count, is_equal_to(10));
assert_that(board->column_count, is_equal_to(15));
assert_that(board->mine_count, is_equal_to(5));
}
即使您使用不同的单元测试框架,总体思路也是相同的。
在您的实际(非测试)代码中,您会调用
get_board_sizes(stdin)
而不是简单地调用 get_board_sizes()
.
您可能需要考虑其他方法来重组
get_board_sizes
以编写针对无效输入的测试。
有什么方法可以测试
功能吗?scanf
是的,你可以从测试返回值开始:如果从用户那里读取了所有 3 个数字,它必须是 3。
函数中还有更多问题:
你不检查
calloc()
失败。
你不检查
scanf()
的返回值:你对无效输入有未定义的行为。
循环
while (getchar() != '\n');
一旦你到达文件末尾就永远不会停止。
不要在
while
/ do
循环的 while
子句中塞满所有值测试,而是使用 for(;;)
(又名 for 循环)和带有有意义的错误消息的显式测试。
这里是修改版:
Board *get_board_sizes(void) {
for (;;) {
int c, count, row_count, column_count, mine_count;
printf("Choose how many rows, columns, and mines you would like\n"
"Note that the maximum number of rows and columns is 30\n"
"and the maximum number of mines is rows*columns\n");
// read user input
count = scanf("%d %d %d", &row_count, &column_count, &mine_count);
// discard the rest of the input line
while ((c = getchar()) != EOF && c != '\n')
continue;
// check input validity
if (count != 3) {
printf("invalid input.\n");
} else
if (row_count < 1 || row_count > 30)
|| column_count < 1 || column_count > 30) {
printf("invalid dimensions\n");
} else
if (mine_count < 1 || mine_count >= row_count * column_count) {
printf("invalid number of mines\n");
} else {
// input is valid: allocate the board, initialize it and return it
Board *board = (Board *)calloc(1, sizeof(*board));
if (board == NULL) {
fprintf(stderr, "allocation failure\n");
return NULL;
}
board->row_count = row_count;
board->column_count = column_count;
board->mine_count = mine_count;
return board;
}
// keep asking the user unless at end of file
if (c == EOF) {
fprintf(stderr, "Unexpected end of file\n");
return NULL;
}
}
}