使用 ctest 在单元测试中重定向标准输出

问题描述 投票:0回答:1

使用

ctest
编写单元测试。要测试的功能是打印输出到 stdout/stderr。 所以,现在,我有:

typedef struct {
  char *stdout_file;
  char *stderr_file;
} test_config;

static int group_setup(void **state) {
  test_config *tc = malloc(sizeof(test_config));
  tc->stdout_file = strdup("/tmp/new_stdout.txt");
  tc->stderr_file = strdup("/tmp/new_stderr.txt");
  *state = tc;
  return 0;
}

static int setup(void **state) {
  test_config *tc = *state;
  if(!freopen(tc->stdout_file, "a+", stdout)) {
     fprintf(stderr, "redirection failed to %s: %m", tc->stdout_file);
     return -1;
  }
  if(!freopen(tc->stderr_file, "a+", stderr)) {
     fprintf(stderr, "redirection failed to %s: %m", tc->stderr_file);
     return -1;
  }
  return 0;
}

static int teardown(void **state) {
  test_config *tc = *state;
  /// How to restore stdout???
  return 0;
}

static int group_teardown(void **state) {
  test_config *tc = *state;
  free(tc->stdout_file);
  free(tc->stderr_file);
  free(tc);
  return 0;
}

static void test(void **state) {
   function_to_test(); // it should always print something to stdout or stderr

   char buffer[LINE_MAX];
   FILE *out = fopen(tc->stdout_file, "r");
   fread(buffer, 1, sizeof(buffer), out);
   fclose(out);

   int rc = memcmp(buffer, expected_output, strlen(expected_output));
   assert_int_equal(rc, 0);
}

int main() {
  const struct CMUnitTest tests[] = {
    cmocka_unit_test_setup_teardown(test, setup, teardown),
  }
  return cmocka_run_group_tests(tests, group_setup, group_teardown);
}

我遇到的问题是用于重定向的文件未创建。但不会打印来自

freopen()
失败的消息。在 LastTest.log 中我看到:

[ RUN ] mytest
<end of output>

这让我相信重定向确实发生了。但文件在哪里?

如何将 stdout/stderr 返回到

ctest
?为什么我在测试日志中看不到
[ PASSED ] mytest

有更好的方法吗?

ctest
不应该已经有一些内置的功能来检查标准输出的内容吗?这是相当普遍的问题,不是吗?

c ctest freopen
1个回答
0
投票

最后我是这样解决这个问题的:

static int setup(void **state) {
   test_config *tc = *state;
   // nothing to do with capturing TTY
   return 0;
}

static int teardown(void **state) {
   test_config *tc = *state;
   unlink(tc->stdout_file);
   unlink(tc->stderr_file);
   return 0;
}

static void capture_tty(void **state) {
   test_config *tc = *state;
   fflush(stdout);
   tc->stdout_fd = dup(STDOUT_FILENO);
   int redir_fd = open(tc->stdout_file, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE);
   dup2(redir_fd, STDOUT_FILENO);
   close(redir_fd);
   // same for stderr
}

static void release_tty(void **state) {
   test_config *tc = *state;
   fflush(stdout);
   dup2(tc->stdout_fd, STDOUT_FILENO);
   close(tc->stdout_fd);
   // same for stderr
}

static void test(void **state) {
   capture_tty(state);
   function_to_test(); // it should always print something to stdout or stderr
   release_tty(state);

   // at this moment, standard streams is back under ctest's control and
   // all assert_*() work as expected.
}

该方法可以完整捕获刚刚测试的函数的 stdout/stderr。同时不干扰

ctest
自己的捕捉。

谢谢各位的指点。

© www.soinside.com 2019 - 2024. All rights reserved.