第一次接触单元测试是在跟着别人做一个json解析器的时候,然后之后又接触了rspec做单元测试,所以趁着国庆假期,我想着把他们总结一下,目前我做的比较简单,另外google test 还没有接触,也想趁着假期简单的入个门。我也希望日后如果接触的更多能够单元测试的案例时,能够记录在这里。
首先是一个基本的框架,,该框架用来统计测test的数量,通过的数量,更多具体细节在test.c · jiawen/myjson
static int main_ret = 0;
static int test_count = 0; // 测试总数
static int test_pass = 0; // 测试通过的数量
// equality 是否相等 expect 期待的输出 actul实际的输出 format数据的格式
#define EXPECT_EQ_BASE(equality, expect, actul, format) \
do{ \
test_count++; \
if(equality){ \
test_pass++; \
} \
else{ \
fprintf(stderr, "[%s]->%d expect: " format" " "actual: " format"\n", __FILE__, __LINE__, expect, actul); \
main_ret = 1; \
} \
}while(0)
#define EXPECT_EQ_INT(expect, actul) EXPECT_EQ_BASE((expect == actul), expect, actul, "%d")
#define EXPECT_EQ_DOUBLE(expect, actul) EXPECT_EQ_BASE((expect == actul), expect, actul, "%.17g")
#define EXPECT_EQ_STRING(expect, actul, length)\
EXPECT_EQ_BASE((sizeof(expect) -1 == length) &&(memcmp(expect, actul, length) == 0), expect, actul, "%s")
// #define EXPECT_TRUE(actul) EXPECT_EQ_BASE(1 == actul, 1, actul, "%d")
// #define EXPECT_FALSE(actul) EXPECT_EQ_BASE(0 == actul, 0, actul, "%d")
#define EXPECT_TRUE(actual) EXPECT_EQ_BASE((actual) != 0, "true", "false", "%s")
#define EXPECT_FALSE(actual) EXPECT_EQ_BASE((actual) == 0, "false", "true", "%s")
2.redis中的小的测试框架
#ifndef __TESTHELP_H
#define __TESTHELP_H
int __failed_tests = 0;
int __test_num = 0;
#define test_cond(descr,_c) do { \
__test_num++; printf("%d - %s: ", __test_num, descr); \
if(_c) printf("PASSED\n"); else {printf("FAILED\n"); __failed_tests++;} \
} while(0);
#define test_report() do { \
printf("%d tests, %d passed, %d failed\n", __test_num, \
__test_num-__failed_tests, __failed_tests); \
if (__failed_tests) { \
printf("=== WARNING === We have failed tests here...\n"); \
exit(1); \
} \
} while(0);
#endif
rspec并不是出现的目的不是为了测试c语言,只是我看他的测试一些简单的东西还是比较容易的,所以想记录一下使用rspec测试c代码的过程。目前做的还比较简单,只是有过接触,当然我也不懂ruby,不过我也期待学习rspec。至于如何安装ruby和rspec,可以看看他的官网,我记得我是自己从源码编译的ruby,然后安装的。(这个有点不好用,不知道为什么,有时候代码可以通过,有时候不可以通过,但是make后就又可以通过了,奇了怪了)
describe 'database' do
before do
`rm -rf test.db`
end
def run_script(commands)
raw_output = nil
IO.popen("./db", "r+") do |pipe|
commands.each do |command|
begin
pipe.puts command
rescue Errno::EPIPE
break
end
end
pipe.close_write
raw_output = pipe.gets(nil)
end
raw_output.split("\n")
end
end
describe 'database' do
before do
`rm -rf test.db`
end
def run_script(commands)
raw_output = nil
IO.popen("./db", "r+") do |pipe|
commands.each do |command|
begin
pipe.puts command
rescue Errno::EPIPE
break
end
end
pipe.close_write
raw_output = pipe.gets(nil)
end
raw_output.split("\n")
end
it 'allows inserting strings that are the maximum length' do
long_username = "a"*32
long_email = "a"*255
script = [
"insert 1 #{long_username} #{long_email}",
"select",
".exit",
]
result = run_script(script)
expect(result).to match_array([
"db > Executed.",
"db > 1 #{long_username} #{long_email}",
"Executed.",
"db > ",
])
end
it 'inserts and retireves a row' do
result = run_script([
"insert 1 user1 [email protected]",
"select",
".exit",
])
expect(result).to match_array([
"db > Executed.",
"db > 1 user1 [email protected]",
"Executed.",
"db > ",
])
end
end
下面是由AI生成的注释:
# 定义一个方法,接受一个命令数组作为参数
def run_script(commands)
# 定义一个变量,用来存储脚本的输出
raw_output = nil
# 使用IO.popen方法,以读写模式打开一个进程,执行db脚本
IO.popen("./db", "r+") do |pipe|
# 遍历命令数组,逐个发送给脚本
commands.each do |command|
begin
# 使用puts方法,将命令写入管道
pipe.puts command
rescue Errno::EPIPE
# 如果发生管道断开的错误,终止循环
# 这段代码非常有用,有时候会出现大量数据输入导致的pipe错误但是这段代码加入后没有问题了。
break
end
end
# 关闭管道的写入端
pipe.close_write
# 从管道的读取端获取所有的输出,赋值给raw_output变量
raw_output = pipe.gets(nil)
end
# 将原始输出按换行符分割,返回一个数组
raw_output.split("\n")
end
基础的部分感觉与自定义的一样,等我具体的使用了在记录一下。