Skip to content

记录一个单测优化 #32

Description

@bingtaoli

问题

和同事配合开发一个功能点。同事给了头文件给我,我这边开发不受阻塞,单测中mock他的接口就可以了。

有个函数A,原型是int A();但是后面他有更新分支了,改了原型变成了int A(bool arg);

那我功能代码里面肯定跟着改了,但是单测里面忘记改了。单测使用如下:

int mockA()
{
    return 0;
}

xreplace((void *A, (void *mockA);

由于转了void*,编译时不会报错的。

实际上功能代码跑到A会调用mockA这个函数,参数其实是不同的。运行单测时,调用A(false),实际上会变成:

  • 压栈false
  • 调用call A,实际上会是call mockA

调用约定是__stdcall
在Win32 Api中,由主调用函数采用从右到左的压栈方式进行参数压栈,然后由被调用者弹栈(pop),被调用者自己在退出时清空堆栈。

所以调用者压栈了false,但是mockA退出时候不会清理堆栈因为他认为自己是没有入参的。这样栈就不平衡了

解决方法

首先肯定是把mockA原型改对。这样确实在win32下跑单测不会蹦了。

有啥更好的拓展吗,怎么预防后面再次出现类似问题?很自然想到单测mock应该限制函数类型一致。

优化mock方法,校验函数原型应该一样:

// 强制函数类型需要一样
#define cpp_xtest_replace(target, hook) \
    do {\
        if (!std::is_same<decltype(target), decltype(hook)>::value) {\
            ASSERT_TRUE(0); \
        }\
        xtest_replace__((void*)target, (void*)hook, #target, #hook);\
    } while (0);

使用:

cpp_xtest_replace(A, mockA);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions