精华内容
下载资源
问答
  • C++打桩测试

    2020-03-27 19:04:22
    一 问题的产生 ...需要进行"打桩",举一个具体的例子 class DataGetter { public: ool Run(); … private: … Client* m_ptr_client; … }; …… …… bool DataGetter::Run() { … std::string da...

    该博文为原创文章,未经博主同意不得转载,如同意转载请注明博文出处
    本文章博客地址:https://cplusplus.blog.csdn.net/article/details/105148200

    一 问题的产生

    当构造测试用例的数据,是在函数内部被另一个外部函数所使用时,我们需要忽略外部函数所带来的影响。

    需要进行"打桩",举一个具体的例子

    class DataGetter
    {
       
    
    public:
        ool Run();
    
            private :
    
            Client *m_ptr_client;
    
    展开全文
  • C++test 打桩

    千次阅读 2014-12-09 12:03:30
    1 打桩 1.1. 编写源代码和测试代码 1.2. 编写桩函数 [Parasoft]-[显示视图]-[桩函数] [选择原始的(函数)]-[右键创建用户桩函数…] 编写用户桩函数 2 源代码 #include int add(int a,int b) {
    1       打桩
    1.1.      编写源代码和测试代码
    1.2.      编写桩函数
    [Parasoft]-[显示视图]-[桩函数]
    [选择原始的(函数)]-[右键创建用户桩函数…]
    编写用户桩函数
    2    源代码
    #include <stdio.h>
    int add(int a,int b)
    {
          return a+b;
    }
    int compare(int a,int b)
    {
           if (a>=b)
                return add(a,b);
           else
                  return add(a,b);
    }
    void main()
    {
           int a=10,b=5;
           int c=compare(a,b);
           printf("%d",c);
           scanf("%c",&c);
    }
    3    测试代码
    #include "cpptest.h"
    CPPTEST_CONTEXT("cpptest/cpptest/源文件/cpptest.cpp");
    CPPTEST_TEST_SUITE_INCLUDED_TO("cpptest/cpptest/源文件/cpptest.cpp");
    class TestSuite2 : public CppTest_TestSuite
    {
       public:
           CPPTEST_TE
    展开全文
  • c++ 单元测试打桩技巧总结(stub、mock)

    万次阅读 2018-03-14 09:50:19
    Stub API 源码地址: ... 说明: - 只适用linux,和windows的x86、x64架构 - access private function相关方法基于C++11(参考:https://github.com/martong/access_private) - replace function相关方法基...

    这里写图片描述


    Stub API 源码地址: https://github.com/coolxv/cpp-stub

    说明:
    - 只适用linux,和windows的x86、x64架构
    - access private function相关方法基于C++11(参考:https://github.com/martong/access_private
    - replace function相关方法基于C++03
    - windows和linux的用法会稍微不同,原因是获取不同类型函数地址的方法不同,且调用约定有时不一样

    不可以打桩的情况:
    - 不可以对exit函数打桩,编译器做了特殊优化
    - 不可以对纯虚函数打桩,纯虚函数没有地址
    - static声明的普通内部函数不能打桩,内部函数地址不可见(解析ELF或许可以获得函数地址)


    普通函数打桩(非static)

    //for linux and windows
    #include<iostream>
    #include "stub.h"
    using namespace std;
    int foo(int a)
    {   
        cout<<"I am foo"<<endl;
        return 0;
    }
    int foo_stub(int a)
    {   
        cout<<"I am foo_stub"<<endl;
        return 0;
    }
    
    
    int main()
    {
        Stub stub;
        stub.set(foo, foo_stub);
        foo(1);
        return 0;
    }
    

    实例成员函数打桩

    //for linux,__cdecl
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
        int i;
    public:
        int foo(int a){
            cout<<"I am A_foo"<<endl;
            return 0;
        }
    };
    
    int foo_stub(void* obj, int a)
    {   
        A* o= (A*)obj;
        cout<<"I am foo_stub"<<endl;
        return 0;
    }
    
    
    int main()
    {
        Stub stub;
        stub.set(ADDR(A,foo), foo_stub);
        A a;
        a.foo(1);
        return 0;
    }
    
    //for windows,__thiscall
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
        int i;
    public:
        int foo(int a){
            cout<<"I am A_foo"<<endl;
            return 0;
        }
    };
    
    
    class B{
    public:
        int foo_stub(int a){
            cout<<"I am foo_stub"<<endl;
            return 0;
        }
    };
    
    int main()
    {
        Stub stub;
        stub.set(ADDR(A,foo), ADDR(B,foo_stub));
        A a;
        a.foo(1);
        return 0;
    }
    

    静态成员函数打桩

    //for linux and windows
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
        int i;
    public:
        static int foo(int a){
            cout<<"I am A_foo"<<endl;
            return 0;
        }
    };
    
    int foo_stub(int a)
    {   
        cout<<"I am foo_stub"<<endl;
        return 0;
    }
    
    
    int main()
    {
        Stub stub;
        stub.set(ADDR(A,foo), foo_stub);
    
        A::foo(1);
        return 0;
    }
    

    模板函数打桩

    //for linux,__cdecl
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
    public:
       template<typename T>
       int foo(T a)
       {   
            cout<<"I am A_foo"<<endl;
            return 0;
       }
    };
    
    int foo_stub(void* obj, int x)
    {   
        A* o= (A*)obj;
        cout<<"I am foo_stub"<<endl;
        return 0;
    }
    
    
    int main()
    {
        Stub stub;
        stub.set((int(A::*)(int))ADDR(A,foo), foo_stub);
        A a;
        a.foo(5);
        return 0;
    }
    
    //for windows,__thiscall
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
    public:
       template<typename T>
       int foo(T a)
       {   
            cout<<"I am A_foo"<<endl;
            return 0;
       }
    };
    
    
    class B {
    public:
        int foo_stub(int a) {
            cout << "I am foo_stub" << endl;
            return 0;
        }
    };
    
    
    int main()
    {
        Stub stub;
        stub.set((int(A::*)(int))ADDR(A,foo), ADDR(B, foo_stub));
        A a;
        a.foo(5);
        return 0;
    }

    重载函数打桩

    //for linux,__cdecl
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
        int i;
    public:
        int foo(int a){
            cout<<"I am A_foo_int"<<endl;
            return 0;
        }
        int foo(double a){
            cout<<"I am A_foo-double"<<endl;
            return 0;
        }
    };
    
    int foo_stub_int(void* obj,int a)
    {   
        A* o= (A*)obj;
        cout<<"I am foo_stub_int"<< a << endl;
        return 0;
    }
    int foo_stub_double(void* obj,double a)
    {   
        A* o= (A*)obj;
        cout<<"I am foo_stub_double"<< a << endl;
        return 0;
    }
    
    int main()
    {
        Stub stub;
        stub.set((int(A::*)(int))ADDR(A,foo), foo_stub_int);
        stub.set((int(A::*)(double))ADDR(A,foo), foo_stub_double);
        A a;
        a.foo(5);
        a.foo(1.1);
        return 0;
    }
    
    //for windows,__thiscall
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
        int i;
    public:
        int foo(int a){
            cout<<"I am A_foo_int"<<endl;
            return 0;
        }
        int foo(double a){
            cout<<"I am A_foo-double"<<endl;
            return 0;
        }
    };
    class B{
        int i;
    public:
        int foo_stub_int(int a)
        {
            cout << "I am foo_stub_int" << a << endl;
            return 0;
        }
        int foo_stub_double(double a)
        {
            cout << "I am foo_stub_double" << a << endl;
            return 0;
        }
    };
    int main()
    {
        Stub stub;
        stub.set((int(A::*)(int))ADDR(A,foo), ADDR(B, foo_stub_int));
        stub.set((int(A::*)(double))ADDR(A,foo), ADDR(B, foo_stub_double));
        A a;
        a.foo(5);
        a.foo(1.1);
        return 0;
    }

    虚函数打桩

    //for linux
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
    public:
        virtual int foo(int a){
            cout<<"I am A_foo"<<endl;
            return 0;
        }
    };
    
    int foo_stub(void* obj,int a)
    {   
        A* o= (A*)obj;
        cout<<"I am foo_stub"<<endl;
        return 0;
    }
    
    
    int main()
    {
        typedef int (*fptr)(A*,int);
        fptr A_foo = (fptr)(&A::foo);   //获取虚函数地址
        Stub stub;
        stub.set(A_foo, foo_stub);
        A a;
        a.foo();
        return 0;
    }
    
    //for windows x86(32位)
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A {
    public:
        virtual int foo(int a) {
            cout << "I am A_foo" << endl;
            return 0;
        }
    };
    
    class B {
    public:
        int foo_stub(int a)
        {
            cout << "I am foo_stub" << endl;
            return 0;
        }
    };
    
    
    
    int main()
    {
        unsigned long addr;
        _asm {mov eax, A::foo}
        _asm {mov addr, eax}
        Stub stub;
        stub.set(addr, ADDR(B, foo_stub));
        A a;
        a.foo(1);
        return 0;
    }
    //for windows x64(64位),VS编译器不支持内嵌汇编。有解决方案自行搜索。

    内联函数打桩

    //for linux
    //添加-fno-inline编译选项,禁止内联,能获取到函数地址,打桩参考上面。
    //for windows
    //添加/Ob0禁用内联展开。

    第三方库私有成员函数打桩

    //for linux
    //被测代码添加-fno-access-private编译选项,禁用访问权限控制,成员函数都为公有的
    //无源码的动态库或静态库无法自己编译,需要特殊技巧获取函数地址
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
        int a;
        int foo(int x){
            cout<<"I am A_foo "<< a << endl;
            return 0;
        }
        static int b;
        static int bar(int x){
            cout<<"I am A_bar "<< b << endl;
            return 0;
        }
    };
    
    
    ACCESS_PRIVATE_FIELD(A, int, a);
    ACCESS_PRIVATE_FUN(A, int(int), foo);
    ACCESS_PRIVATE_STATIC_FIELD(A, int, b);
    ACCESS_PRIVATE_STATIC_FUN(A, int(int), bar);
    
    int foo_stub(void* obj, int x)
    {   
        A* o= (A*)obj;
        cout<<"I am foo_stub"<<endl;
        return 0;
    }
    int bar_stub(int x)
    {   
        cout<<"I am bar_stub"<<endl;
        return 0;
    }
    int main()
    {
        A a;
    
        auto &A_a = access_private_field::Aa(a);
        auto &A_b = access_private_static_field::A::Ab();
        A_a = 1;
        A_b = 10;
    
        call_private_fun::Afoo(a,1);
        call_private_static_fun::A::Abar(1);
    
        auto A_foo= get_private_fun::Afoo();
        auto A_bar = get_private_static_fun::A::Abar();
    
        Stub stub;
        stub.set(A_foo, foo_stub);
        stub.set(A_bar, bar_stub);
    
        call_private_fun::Afoo(a,1);
        call_private_static_fun::A::Abar(1);
        return 0;
    }
    //for windows,__thiscall
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
        int a;
        int foo(int x){
            cout<<"I am A_foo "<< a << endl;
            return 0;
        }
        static int b;
        static int bar(int x){
            cout<<"I am A_bar "<< b << endl;
            return 0;
        }
    };
    
    
    ACCESS_PRIVATE_FIELD(A, int, a);
    ACCESS_PRIVATE_FUN(A, int(int), foo);
    ACCESS_PRIVATE_STATIC_FIELD(A, int, b);
    ACCESS_PRIVATE_STATIC_FUN(A, int(int), bar);
    class B {
    public:
        int foo_stub(int x)
        {
            cout << "I am foo_stub" << endl;
            return 0;
        }
    };
    int bar_stub(int x)
    {   
        cout<<"I am bar_stub"<<endl;
        return 0;
    }
    
    
    int main()
    {
        A a;
    
        auto &A_a = access_private_field::Aa(a);
        auto &A_b = access_private_static_field::A::Ab();
        A_a = 1;
        A_b = 10;
    
        call_private_fun::Afoo(a,1);
        call_private_static_fun::A::Abar(1);
    
        auto A_foo= get_private_fun::Afoo();
        auto A_bar = get_private_static_fun::A::Abar();
    
        Stub stub;
        stub.set(A_foo, ADDR(B,foo_stub));
        stub.set(A_bar, bar_stub);
    
        call_private_fun::Afoo(a,1);
        call_private_static_fun::A::Abar(1);
        return 0;
    }
    展开全文
  •  打桩的目的 打桩的目的主要有:隔离、补齐、控制。 隔离是指将测试任务从产品项目中分离出来,使之能够独立编译、链接,并独立运行。隔离的基本方法就是打桩,将测试任务之外的,并且与测试任务相关的代码,用.....

    什么是桩

           桩,或称桩代码,是指用来代替关联代码或者未实现代码的代码。如果函数B用B1来代替,那么,B称为原函数,B1称为桩函数。打桩就是编写或生成桩代码。

           打桩的目的

           打桩的目的主要有:隔离、补齐、控制。

           隔离是指将测试任务从产品项目中分离出来,使之能够独立编译、链接,并独立运行。隔离的基本方法就是打桩,将测试任务之外的,并且与测试任务相关的代码,用桩来代替,从而实现分离测试任务。例如函数A调用了函数B,函数B又调用了函数C和D,如果函数B用桩来代替,函数A就可以完全割断与函数C和D的关系。

           补齐是指用桩来代替未实现的代码,例如,函数A调用了函数B,而函数B由其他程序员编写,且未实现,那么,可以用桩来代替函数B,使函数A能够运行并测试。补齐在并行开发中很常用。

           控制是指在测试时,人为设定相关代码的行为,使之符合测试需求。例如:

    externint B();

     

    int A()

    {

          int ret = B();

          if(ret == 0)

               ;//do something

        elseif(ret == 1)

               ;//do something

        else

               ;//do something

     

          return ret;

    }

     

            如果函数B返回随机数,或者返回网络状态,或者返回环境温度,等等,则当调用其实际代码时,函数A很难测试,这时可以用桩函数B1来代替B,使其返回测试所需要的数据。

            一个桩函数,可能既具有控制功能,又具有隔离或补齐功能。

            编写桩

            一般来说,桩函数要具有与原函数完全一致的原形,仅仅是实现不同,这样测试代码才能正确链接到桩函数。

            用于实现隔离和补齐的桩函数一般比较简单,只需把原函数的声明拷过来,加一个空的实现,能通过编译链接就行了。

           比较复杂的是实现控制功能的桩函数,要根据测试的需要,输出合适的数据,下面是一个示例:

    //获取环境温度。温度由出参pTemperature输出,返回值表示获取温度是否成功,如果成功,则返回1,否则返回0。

    int GetTemperature(int* pTemperature)

    {

          if(caseNameIs("failed"))

               return 0;

     

          if(caseNameIs("ok-23"))

          {

               *pTemperature = 23;

               return 1;

          }

     

          if(caseNameIs("ok-25"))

          {

               *pTemperature = 25;

               return 1;

          }

     

          if(caseNameIs("ok-28"))

          {

               *pTemperature = 28;

               return 1;

          }

     

          return 0;

    }

     

           其中,caseNameIs()是由测试工具提供的API,用于判断用例的名称。代码根据用例名称来决定输出数据。

    自然输入:自然输入调用实际代码,不需要特别解决,跟桩无关。

              不可控:不可控调用的也是实际代码,并不调用桩代码,因此也不能解决。另外编写桩代码来代替实际代码行不行?在应该调用实际代码的时候,要想调用桩代码可能很麻烦,例如,底层函数位于同一个文件,或同一个类,通常要用编译条件来区分实际代码和桩代码,不但麻烦,而且污染产品代码。

    难于初始化:也是调用实际代码。

              静态输入:静态输入只涉及到局部静态变量,没有调用底层函数,当然也不能用桩来代替。

             中断输入:中断输入是在不确定位置,中断调用不确定的代码形成的,也不能用桩来代替。

             失真:失真是打桩造成的,调用的是桩代码。在比较简单的情形下,可以用命名法来控制桩代码的输出,即给每个用例命名,桩代码中判断用例名来决定输出,具体方法在前文已经介绍过。如果在同一个用例中,多次调用同一个桩,每次要求输出不同,命名法就无效了。这种情形是很常见的,例如一个函数多次调用同一个底层函数,或在循环中调用桩代码。一个被测函数可能调用多个桩,一个桩又可能被多个被测函数调用,这种多对多的关系下,很难维护用例与桩的对应。用例可能很多,还可能要不断增加和修改,维护用例与桩输出的关系也很麻烦。

       

           总之,在实际的应用中,在测试的时间成本受限的情形下,编写桩代码一般只能解决部分失真,难以适应复杂的应用。

            一、采用自底向上的开发策略,先开发和测试底层代码,当测试上层代码时,假设底层代码是正确的,直接调用底层代码,从而减少打桩。

            二、在隔离测试任务时将源文件分为三类:被测文件、外围文件、隔离文件。被测文件是指测试任务内的源文件;外围文件是指不测试或由其他人测试,但与被测文件关系密切的源文件;其他文件为隔离文件。外围文件与被测文件一起进行编译链接,测试时调用实际代码,从而减少打桩。

    三、使用自动化工具。编写以隔离和补齐为目的的桩,是一种简单重复的工作,由工具生成最为合适。至于控制目的的桩代码,工具无法自动生成,但是,工具可以提供更为先进的方式,如底层模拟。底层模拟可以让桩输出像参数一样,在用例中设定,从而大幅减少单元测试的时间成本。

    这里写图片描述


    Stub API 源码地址: https://github.com/coolxv/cpp-stub

    说明: 
    - 只适用linux,和windows的x86、x64架构 
    - access private function相关方法基于C++11(参考:https://github.com/martong/access_private) 
    - replace function相关方法基于C++03 
    - windows和linux的用法会稍微不同,原因是获取不同类型函数地址的方法不同,且调用约定有时不一样

    不可以打桩的情况: 
    - 不可以对exit函数打桩,编译器做了特殊优化 
    - 不可以对纯虚函数打桩,纯虚函数没有地址 
    - static声明的普通内部函数不能打桩,内部函数地址不可见(解析ELF或许可以获得函数地址)


    普通函数打桩(非static)

    //for linux and windows
    #include<iostream>
    #include "stub.h"
    using namespace std;
    int foo(int a)
    {   
        cout<<"I am foo"<<endl;
        return 0;
    }
    int foo_stub(int a)
    {   
        cout<<"I am foo_stub"<<endl;
        return 0;
    }
    
    
    int main()
    {
        Stub stub;
        stub.set(foo, foo_stub);
        foo(1);
        return 0;
    }
    

    实例成员函数打桩

    //for linux,__cdecl
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
        int i;
    public:
        int foo(int a){
            cout<<"I am A_foo"<<endl;
            return 0;
        }
    };
    
    int foo_stub(void* obj, int a)
    {   
        A* o= (A*)obj;
        cout<<"I am foo_stub"<<endl;
        return 0;
    }
    
    
    int main()
    {
        Stub stub;
        stub.set(ADDR(A,foo), foo_stub);
        A a;
        a.foo(1);
        return 0;
    }
    

    //for windows,__thiscall
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
        int i;
    public:
        int foo(int a){
            cout<<"I am A_foo"<<endl;
            return 0;
        }
    };
    
    
    class B{
    public:
        int foo_stub(int a){
            cout<<"I am foo_stub"<<endl;
            return 0;
        }
    };
    
    int main()
    {
        Stub stub;
        stub.set(ADDR(A,foo), ADDR(B,foo_stub));
        A a;
        a.foo(1);
        return 0;
    }
    

    静态成员函数打桩

    //for linux and windows
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
        int i;
    public:
        static int foo(int a){
            cout<<"I am A_foo"<<endl;
            return 0;
        }
    };
    
    int foo_stub(int a)
    {   
        cout<<"I am foo_stub"<<endl;
        return 0;
    }
    
    
    int main()
    {
        Stub stub;
        stub.set(ADDR(A,foo), foo_stub);
    
        A::foo(1);
        return 0;
    }
    

    模板函数打桩

    //for linux,__cdecl
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
    public:
       template<typename T>
       int foo(T a)
       {   
            cout<<"I am A_foo"<<endl;
            return 0;
       }
    };
    
    int foo_stub(void* obj, int x)
    {   
        A* o= (A*)obj;
        cout<<"I am foo_stub"<<endl;
        return 0;
    }
    
    
    int main()
    {
        Stub stub;
        stub.set((int(A::*)(int))ADDR(A,foo), foo_stub);
        A a;
        a.foo(5);
        return 0;
    }
    

    //for windows,__thiscall
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
    public:
       template<typename T>
       int foo(T a)
       {   
            cout<<"I am A_foo"<<endl;
            return 0;
       }
    };
    
    
    class B {
    public:
        int foo_stub(int a) {
            cout << "I am foo_stub" << endl;
            return 0;
        }
    };
    
    
    int main()
    {
        Stub stub;
        stub.set((int(A::*)(int))ADDR(A,foo), ADDR(B, foo_stub));
        A a;
        a.foo(5);
        return 0;
    }

    重载函数打桩

    //for linux,__cdecl
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
        int i;
    public:
        int foo(int a){
            cout<<"I am A_foo_int"<<endl;
            return 0;
        }
        int foo(double a){
            cout<<"I am A_foo-double"<<endl;
            return 0;
        }
    };
    
    int foo_stub_int(void* obj,int a)
    {   
        A* o= (A*)obj;
        cout<<"I am foo_stub_int"<< a << endl;
        return 0;
    }
    int foo_stub_double(void* obj,double a)
    {   
        A* o= (A*)obj;
        cout<<"I am foo_stub_double"<< a << endl;
        return 0;
    }
    
    int main()
    {
        Stub stub;
        stub.set((int(A::*)(int))ADDR(A,foo), foo_stub_int);
        stub.set((int(A::*)(double))ADDR(A,foo), foo_stub_double);
        A a;
        a.foo(5);
        a.foo(1.1);
        return 0;
    }
    

    //for windows,__thiscall
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
        int i;
    public:
        int foo(int a){
            cout<<"I am A_foo_int"<<endl;
            return 0;
        }
        int foo(double a){
            cout<<"I am A_foo-double"<<endl;
            return 0;
        }
    };
    class B{
        int i;
    public:
        int foo_stub_int(int a)
        {
            cout << "I am foo_stub_int" << a << endl;
            return 0;
        }
        int foo_stub_double(double a)
        {
            cout << "I am foo_stub_double" << a << endl;
            return 0;
        }
    };
    int main()
    {
        Stub stub;
        stub.set((int(A::*)(int))ADDR(A,foo), ADDR(B, foo_stub_int));
        stub.set((int(A::*)(double))ADDR(A,foo), ADDR(B, foo_stub_double));
        A a;
        a.foo(5);
        a.foo(1.1);
        return 0;
    }

    虚函数打桩

    //for linux
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
    public:
        virtual int foo(int a){
            cout<<"I am A_foo"<<endl;
            return 0;
        }
    };
    
    int foo_stub(void* obj,int a)
    {   
        A* o= (A*)obj;
        cout<<"I am foo_stub"<<endl;
        return 0;
    }
    
    
    int main()
    {
        typedef int (*fptr)(A*,int);
        fptr A_foo = (fptr)(&A::foo);   //获取虚函数地址
        Stub stub;
        stub.set(A_foo, foo_stub);
        A a;
        a.foo();
        return 0;
    }
    

    //for windows x86(32位)
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A {
    public:
        virtual int foo(int a) {
            cout << "I am A_foo" << endl;
            return 0;
        }
    };
    
    class B {
    public:
        int foo_stub(int a)
        {
            cout << "I am foo_stub" << endl;
            return 0;
        }
    };
    
    
    
    int main()
    {
        unsigned long addr;
        _asm {mov eax, A::foo}
        _asm {mov addr, eax}
        Stub stub;
        stub.set(addr, ADDR(B, foo_stub));
        A a;
        a.foo(1);
        return 0;
    }

    //for windows x64(64位),VS编译器不支持内嵌汇编。有解决方案自行搜索。

    内联函数打桩

    //for linux
    //添加-fno-inline编译选项,禁止内联,能获取到函数地址,打桩参考上面。

    //for windows
    //添加/Ob0禁用内联展开。

    第三方库私有成员函数打桩

    //for linux
    //被测代码添加-fno-access-private编译选项,禁用访问权限控制,成员函数都为公有的
    //无源码的动态库或静态库无法自己编译,需要特殊技巧获取函数地址
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
        int a;
        int foo(int x){
            cout<<"I am A_foo "<< a << endl;
            return 0;
        }
        static int b;
        static int bar(int x){
            cout<<"I am A_bar "<< b << endl;
            return 0;
        }
    };
    
    
    ACCESS_PRIVATE_FIELD(A, int, a);
    ACCESS_PRIVATE_FUN(A, int(int), foo);
    ACCESS_PRIVATE_STATIC_FIELD(A, int, b);
    ACCESS_PRIVATE_STATIC_FUN(A, int(int), bar);
    
    int foo_stub(void* obj, int x)
    {   
        A* o= (A*)obj;
        cout<<"I am foo_stub"<<endl;
        return 0;
    }
    int bar_stub(int x)
    {   
        cout<<"I am bar_stub"<<endl;
        return 0;
    }
    int main()
    {
        A a;
    
        auto &A_a = access_private_field::Aa(a);
        auto &A_b = access_private_static_field::A::Ab();
        A_a = 1;
        A_b = 10;
    
        call_private_fun::Afoo(a,1);
        call_private_static_fun::A::Abar(1);
    
        auto A_foo= get_private_fun::Afoo();
        auto A_bar = get_private_static_fun::A::Abar();
    
        Stub stub;
        stub.set(A_foo, foo_stub);
        stub.set(A_bar, bar_stub);
    
        call_private_fun::Afoo(a,1);
        call_private_static_fun::A::Abar(1);
        return 0;
    }
    for windows,__thiscall
    #include<iostream>
    #include "stub.h"
    using namespace std;
    class A{
        int a;
        int foo(int x){
            cout<<"I am A_foo "<< a << endl;
            return 0;
        }
        static int b;
        static int bar(int x){
            cout<<"I am A_bar "<< b << endl;
            return 0;
        }
    };
    
    
    ACCESS_PRIVATE_FIELD(A, int, a);
    ACCESS_PRIVATE_FUN(A, int(int), foo);
    ACCESS_PRIVATE_STATIC_FIELD(A, int, b);
    ACCESS_PRIVATE_STATIC_FUN(A, int(int), bar);
    class B {
    public:
        int foo_stub(int x)
        {
            cout << "I am foo_stub" << endl;
            return 0;
        }
    };
    int bar_stub(int x)
    {   
        cout<<"I am bar_stub"<<endl;
        return 0;
    }
    
    
    int main()
    {
        A a;
    
        auto &A_a = access_private_field::Aa(a);
        auto &A_b = access_private_static_field::A::Ab();
        A_a = 1;
        A_b = 10;
    
        call_private_fun::Afoo(a,1);
        call_private_static_fun::A::Abar(1);
    
        auto A_foo= get_private_fun::Afoo();
        auto A_bar = get_private_static_fun::A::Abar();
    
        Stub stub;
        stub.set(A_foo, ADDR(B,foo_stub));
        stub.set(A_bar, bar_stub);
    
        call_private_fun::Afoo(a,1);
        call_private_static_fun::A::Abar(1);
        return 0;
    }

    展开全文
  • C++单元测试--打桩测试

    万次阅读 2014-06-06 20:47:05
    一 问题的产生 当构造测试用例的数据,是在函数内部被另一个外部... 需要进行“打桩”,举一个具体的例子 class DataGetter { public: ... bool Run(); ... private: ... Client* m_ptr_client; ... }; ..... ..... b
  • 敏捷开发,非常强调效率。...如下代码,通过宏开关来控制桩函数,虽然功能上能够达到打桩的效果,但是对待测代码增加了大量的宏,影响代码的可读性。 int Fun1() { return 12; } int Fun() { #ifdef STUB_...
  • C++内建函数是一种编译器特殊函数,它的行为类似与C++的内联函数,但是由于它是编译器提供的,所以编译器对其更加了解更利于优化。 比如说memcpy等就是内在函数。如果编译器有选择/Optimization,那么编译器在生成...
  • 在如下的fun函数中存在printf语句,如果下面的代码片段想要达到100%的覆盖率,则需要考虑打桩printf函数,并且在桩中修改参数d所指向的值。 int fun(int a, int b) {char d[10] = "hello";//char d[10];printf(...
  • Date: 2017/9/9 桩函数(Stub)是模拟被测试模块所调用的模块。 什么是桩 ... 桩,或称桩代码,是指用来代替关联代码或者未实现代码的代码。...隔离的基本方法就是打桩,将测试任务之外的,并...
  • 打桩代码函数

    2015-08-24 20:59:01
    打桩代码函数,c++版本的,希望对大家有帮助。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 531
精华内容 212
关键字:

c++打桩

c++ 订阅