Как мне написать функцию тестирования для другой функции, которая использует ввод stdin? - PullRequest
3 голосов
/ 21 апреля 2011

У меня есть следующие функции в рамках задания колледжа:

int readMenuOption()
{
   /* local declarations */
   char option[2];
   /* read in 1 char from stdin plus 1 char for string termination character */
   readStdin(1 + 1, option);
   return (int)option[0] <= ASCII_OFFSET ? 0 : (int)option[0] - ASCII_OFFSET;
}

int readStdin(int limit, char *buffer) 
{
   char c;
   int i = 0;
   int read = FALSE;
   while ((c = fgetc(stdin)) != '\n') {
      /* if the input string buffer has already reached it maximum
       limit, then abandon any other excess characters. */
      if (i <= limit) {
         *(buffer + i) = c;
         i++;
         read = TRUE;
      }
   }
   /* clear the remaining elements of the input buffer with a null character. */
   for (i = i; i < strlen(buffer); i++) {
      *(buffer + i) = '\0';
   }
   return read;
}

Он отлично работает для того, что мне нужно (принять ввод с клавиатуры). Мне пришлось сделать это с помощью стандартного ввода (как и я) из-за ряда требований, изложенных моим профессором.

Я хочу написать серию «модульных тестов» для задания, но я не знаю, как заставить мои функции тестирования вызывать readMenuOption() и передавать входные данные (без необходимости делать это во время выполнения) .

Возможно ли это, и если да, то как я могу это сделать? (т. е. можно ли написать на стандартный ввод)?

Ответы [ 3 ]

5 голосов
/ 21 апреля 2011

Одна вещь, которую вы могли бы сделать, это просто изменить readStdin, чтобы он мог либо получать данные из реального стандартного ввода, либо из вспомогательной функции, например:

char *fakeStdIn = "";
int myfgetc (FILE *fin) {
    if (*fakeStdIn == '\0')
        return fgetc (fin);
    return *fakeStdIn++;
}

int readStdin(int limit, char *buffer) 
{
   char c;
   int i = 0;
   int read = FALSE;
   while ((c = myfgetc(stdin)) != '\n') {
      /* if the input string buffer has already reached it maximum
       limit, then abandon any other excess characters. */
      if (i <= limit) {
         *(buffer + i) = c;
         i++;
         read = TRUE;
      }
   }
   /* clear the remaining elements of the input buffer with a null character. */
   for (i = i; i < strlen(buffer); i++) {
      *(buffer + i) = '\0';
   }
   return read;
}

Затем, чтобы вызвать его из вашего юнит-теста, вы можете сделать:

fakeStdIn = "1\npaxdiablo\nnice guy\n";
// Call your top-level input functions like  readMenuOption().

Установив ловушку на нижних уровнях, вы можете ввести собственную последовательность символов вместо стандартного ввода. И если в любой момент фальшивый стандартный ввод исчерпан, он возвращается к реальному.

Очевидно, что используются символы, поэтому, если вы хотите внедрить события EOF, вам понадобится массив целых чисел, но это будет незначительной модификацией схемы.

1 голос
/ 21 апреля 2011

Поиск нестандартной, но чрезвычайно полезной функции forkpty.Затем сделайте что-то вроде:

int ptyfd;
pid = forkpty(&ptyfd, 0, 0, 0);
if (pid<0) perror("forkpty"), exit(1);
if (!pid) {
    /* call your function to be tested */
    _exit(1);
} else {
    /* write to ptyfd here to generate input for the function */
}

Обратите внимание, что это позволит вам протестировать вашу функцию точно так же, как если бы она читала с интерактивного терминала.Если вам не нужен этот уровень тестирования, вы можете вместо этого использовать простой канал.

0 голосов
/ 21 апреля 2011

Почему вы не можете использовать перенаправление? Что-то вроде:

./a.out < input.txt

Где "input.txt" будет содержать любой ввод, который вы хотите дать программе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...