C中的文件IO单元测试

C中的文件IO单元测试,c,unit-testing,logging,io,C,Unit Testing,Logging,Io,我需要为一个用C实现的简单记录器编写单元测试(单元测试用C++) 我正在寻找一种方法来模拟对日志文件不成功的“写入”,以便查看记录器是否正确响应并返回错误。 在写入日志文件之前,我尝试重命名日志文件: static bool fileWriteMiss() { const char* testFile = "missLogFile.log"; const char* movedFile = "missedLogFile.log"; ASSERT_TRUE( spLogge

我需要为一个用C实现的简单记录器编写单元测试(单元测试用C++)

我正在寻找一种方法来模拟对日志文件不成功的“写入”,以便查看记录器是否正确响应并返回错误。 在写入日志文件之前,我尝试重命名日志文件:

static bool fileWriteMiss() {
  const char* testFile = "missLogFile.log";
  const char* movedFile = "missedLogFile.log";
  ASSERT_TRUE(
      spLoggerCreate(testFile, SP_LOGGER_DEBUG_INFO_WARNING_ERROR_LEVEL) ==
      SP_LOGGER_SUCCESS);
  rename(testFile, movedFile);
  ASSERT_TRUE(spLoggerPrintError("MSGA", "sp_logger_unit_test.c", __func__,
                                 __LINE__) == SP_LOGGER_WRITE_FAIL);

  spLoggerDestroy();

  return true;
}
static bool fileWriteMiss() {
  const char* testFile = "missLogFile.log";
  ASSERT_TRUE(
      spLoggerCreate(testFile, SP_LOGGER_DEBUG_INFO_WARNING_ERROR_LEVEL) ==
      SP_LOGGER_SUCCESS);
  remove(testFile);
  ASSERT_TRUE(spLoggerPrintError("MSGA", "sp_logger_unit_test.c", __func__,
                                 __LINE__) == SP_LOGGER_WRITE_FAIL);

  spLoggerDestroy();

  return true;
}
在写入日志文件之前,我尝试删除日志文件:

static bool fileWriteMiss() {
  const char* testFile = "missLogFile.log";
  const char* movedFile = "missedLogFile.log";
  ASSERT_TRUE(
      spLoggerCreate(testFile, SP_LOGGER_DEBUG_INFO_WARNING_ERROR_LEVEL) ==
      SP_LOGGER_SUCCESS);
  rename(testFile, movedFile);
  ASSERT_TRUE(spLoggerPrintError("MSGA", "sp_logger_unit_test.c", __func__,
                                 __LINE__) == SP_LOGGER_WRITE_FAIL);

  spLoggerDestroy();

  return true;
}
static bool fileWriteMiss() {
  const char* testFile = "missLogFile.log";
  ASSERT_TRUE(
      spLoggerCreate(testFile, SP_LOGGER_DEBUG_INFO_WARNING_ERROR_LEVEL) ==
      SP_LOGGER_SUCCESS);
  remove(testFile);
  ASSERT_TRUE(spLoggerPrintError("MSGA", "sp_logger_unit_test.c", __func__,
                                 __LINE__) == SP_LOGGER_WRITE_FAIL);

  spLoggerDestroy();

  return true;
}
ASSERT\u TRUE函数在假定正常工作的断言库中实现


spLoggerCreate是记录器结构的初始化函数(我注意不要将其称为构造和对象,因为实现不是oop,而是纯C代码)

一个有效的方法是写入您无法写入的文件(请注意,您可以写入现有目录中不存在的文件-它将被创建)。有几种方法,有些依赖于操作系统:

  • 写入不存在目录中的文件。虽然在一般情况下很复杂,但您可以使用一些技巧,例如使用文件名中不太可能遇到的字符,如“\x01”

    const char*testFile=“不存在\x01dir/missLogFile.log”

  • 写入您没有写入权限的文件。在UNIX中,您可以发出

    chmod a-w file.log

    对现有文件执行命令以撤消写入权限

  • 写入系统只读伪文件

    const char*testFile=“/proc/uptime”//linux

    const char*testFile=“CLOCK$”;//windows/dos

我相信单元测试永远不应该访问操作系统,这样您的测试就变成了非单元测试,但这是一个术语问题,也是一个神圣的战争主题

更新:

你的评论实际上使它成为一个问得不好但很有趣的问题。我想你可以编辑它,我会尝试回答。随着这里的事情越来越复杂,我将只关注Linux,回答这个问题

如何使文件打开以便写入成功,但后续写入失败?

实际应用程序面临的最常见错误可能是“设备上没有空间”。这很容易以密封的方式复制:让我们在本地文件中创建一个fat16文件系统,确切地说:

$ dd if=/dev/urandom of=test_disk bs=1048576 count=1
$ mkdosfs test_disk
$ mkdir /tmp/mnt
$ sudo mount -o loop,rw,umask=000 test_disk /tmp/mnt/
现在填充文件系统。或者我们可以使用更小的尺寸

$ perl -e 'print "a"x(1024*1002)' > /tmp/mnt/a.txt
$ echo test > /tmp/mnt/test || echo "can't write test file"
最后遇到了错误:

$ echo `perl -e 'print "a"x4096'` > /tmp/mnt/test || echo "test succeeded"
bash: echo: write error: No space left on device
test succeeded
准确地说,写入字节1009时遇到错误:

$ ls -l /tmp/mnt/
total 1004
-rwxrwxrwx 1 root root 1026048 Mar 27 17:56 a.txt
-rwxrwxrwx 1 root root    1009 Mar 27 17:57 test

FAT文件系统的一个很好的副作用是,现在您可以自由地在那里打开更多文件,并且按照您的要求,从字节0开始写入将失败。

C不支持方法。和<代码> AdjtTrase看起来不一样。单元测试是用C++编写的。如果这是C++代码,请使用正确的标签!然而,它不是一种方法。出于好奇,为什么要从日志消息返回错误?我从来没有见过一个程序来检查每次日志写入是否成功。人们通常更喜欢对性能影响最小的“优雅失败”。老实说,这是从我在软件课上的一项作业开始的。事实证明,这并不是真正需要的,但我现在把它作为一项教育挑战来解决。当然这里有大量的冗余,但是——我要让它工作起来!我希望能够打开文件,但无法写入。您的建议甚至不允许我打开该文件(+第一个已实现:))