C ++ High-Performance Unit Testing with Google Mock?

I am using Google Mock and I am struggling to mock C ++ system calls (in particular, the Chrono C ++ 11 functions).

I know that I have to make an interface, create a class to implement the interface for my real implementation, and then mock the interface on my tests. I'm trying to write an embedded application, so this level of indirection sounds too expensive for me.

What is the most efficient / effective way to incorporate system calls into Google Mock?

+4
source share
2 answers

, - .

, , / , 3 .

, std::this_thread, sleep_for(std::milliseconds).

0 -

, :

class untestable_class
{
public:

    void some_function()
    {
        if (must_sleep())
        {
            auto sleep_duration = std::chrono::milliseconds(1000);
            std::this_thread::sleep_for(sleep_duration);
        }
    }
};

:

void use_untestable_class()
{
    untestable_class instance;
    instance.some_function();
}

- sleep_for, , some_function unit test, .

1 -

, . , - , /.

"" , :

struct system_thread_policy1
{
    static void sleep_milliseconds(long milliseconds)
    {
        auto sleep_duration = std::chrono::milliseconds(milliseconds);
        std::this_thread::sleep_for(sleep_duration);
    }
};

"" , :

struct mock_thread_policy1
{
    // Mock attributes to verify interactions.
    static size_t sleep_milliseconds_count;
    static size_t sleep_milliseconds_arg1;

    // Resets the mock attributes before usage.
    static void sleep_milliseconds_reset()
    {
        sleep_milliseconds_count = 0;
        sleep_milliseconds_arg1 = 0;
    }

    static void sleep_milliseconds(size_t milliseconds)
    {
        sleep_milliseconds_count++;
        sleep_milliseconds_arg1 = milliseconds;
    }
};

// This is needed with MS compilers to keep all mock code in a header file.
__declspec(selectany) size_t mock_thread_policy1::sleep_milliseconds_count;
__declspec(selectany) size_t mock_thread_policy1::sleep_milliseconds_arg1;

, , sleep_milliseconds :

template <typename thread_policy>
class testable_class1
{
public:

    void some_function()
    {
        if (must_sleep())
        {
            thread_policy::sleep_milliseconds(sleep_duration_milliseconds);
        }
    }

private:

    enum { sleep_duration_milliseconds = 1000 };
};

testable_class1 "" :

void use_testable_class1()
{
    testable_class1<system_thread_policy1> instance;
    instance.some_function();
}

unit test, testable_class1 "mock" :

void test_testable_class1()
{
    mock_thread_policy1::sleep_milliseconds_reset();
    testable_class1<mock_thread_policy1> instance;
    instance.some_function();

    assert(mock_thread_policy1::sleep_milliseconds_count == 1);
    assert(mock_thread_policy1::sleep_milliseconds_arg1 == 1000);
    //assert("some observable behavior on instance");
}

:

  • , , .
  • "" sleep_for.

:

  • .
  • reset unit test, , .
  • , , , .

2 -

"" , :

struct system_thread_policy2
{
    void sleep_milliseconds(size_t milliseconds) const
    {
        auto sleep_duration = std::chrono::milliseconds(milliseconds);
        std::this_thread::sleep_for(sleep_duration);
    }
};

"" , :

struct mock_thread_policy2
{
    mutable size_t sleep_milliseconds_count;
    mutable size_t sleep_milliseconds_arg1;

    mock_thread_policy2()
        : sleep_milliseconds_count(0)
        , sleep_milliseconds_arg1(0)
    {
    }

    void sleep_milliseconds(size_t milliseconds) const
    {
        sleep_milliseconds_count++;
        sleep_milliseconds_arg1 = milliseconds;
    }
};

, , , , , sleep_milliseconds:

template <typename thread_policy>
class testable_class2
{
public:

    testable_class2(const thread_policy& policy = thread_policy()) : m_thread_policy(policy) { }

    void some_function() const
    {
        if (must_sleep())
        {
            m_thread_policy.sleep_milliseconds(sleep_duration_milliseconds);
        }
    }

private:

    // Needed since the thread policy is taken as a reference.
    testable_class2(const testable_class2&);
    testable_class2& operator=(const testable_class2&);

    enum { sleep_duration_milliseconds = 1000 };

    const thread_policy& m_thread_policy;
};

testable_class2 "" :

void use_testable_class2()
{
    const testable_class2<system_thread_policy2> instance;
    instance.some_function();
}

unit test, testable_class2 "mock" :

void test_testable_class2()
{
    mock_thread_policy2 thread_policy;
    const testable_class2<mock_thread_policy2> instance(thread_policy);
    instance.some_function();

    assert(thread_policy.sleep_milliseconds_count == 1);
    assert(thread_policy.sleep_milliseconds_arg1 == 1000);
    //assert("some observable behavior on instance");
}

:

  • , , .
  • "" sleep_for.
    • mocks , , .

:

  • .
  • (testable_class2) - , , goo .

3 -

, , / , , .

-, , "" :

class testable_class3
{
public:

    void some_function()
    {
        if (must_sleep())
        {
            sleep_milliseconds(sleep_duration_milliseconds);
        }
    }

private:

    virtual void sleep_milliseconds(size_t milliseconds)
    {
        auto sleep_duration = std::chrono::milliseconds(milliseconds);
        std::this_thread::sleep_for(sleep_duration);
    }

    enum { sleep_duration_milliseconds = 1000 };
};

-, , "" ( ):

class mock_testable_class3 : public testable_class3
{
public:

    size_t sleep_milliseconds_count;
    size_t sleep_milliseconds_arg1;

    mock_testable_class3()
        : sleep_milliseconds_count(0)
        , sleep_milliseconds_arg1(0)
    {
    }

private:

    virtual void sleep_milliseconds(size_t milliseconds)
    {
        sleep_milliseconds_count++;
        sleep_milliseconds_arg1 = milliseconds;
    }
};

testable_class3 :

void use_testable_class3()
{
    // Lots of opportunities to optimize away the virtual dispatch.
    testable_class3 instance;
    instance.some_function();
}

unit test, testable_class3 "mock" :

void test_testable_class3()
{
    mock_testable_class3 mock_instance;
    auto test_function = [](testable_class3& instance) { instance.some_function(); };
    test_function(mock_instance);

    assert(mock_instance.sleep_milliseconds_count == 1);
    assert(mock_instance.sleep_milliseconds_arg1 == 1000);
    //assert("some observable behavior on mock_instance");
}

:

  • , , .
  • "" "" sleep_for.
  • mocks , , .

:

  • final (++ 11), , , , .
  • / .

Test Run

:

int _tmain(int argc, _TCHAR* argv[])
{
    test_testable_class1();
    test_testable_class2();
    test_testable_class3();

    return 0;
}

runnable - http://pastebin.com/0qJaQVcD

+3

, , -. .

, . - :

struct SysCallCaller
{
    static void doCall()
    {
        // really execute system call
    }
    private:
    SysCallCaller();
};

struct SysCallMock
{
    static void doCall()
    {
        // mock system call
    }
};

template < typename SysCallType >
struct MyClass
{
    void Foo()
    {
        SysCallType::doCall();
    }

};

int main()
{
#ifdef CALL_MOCK
    MyClass< SysCallMock > obj;
#else
    MyClass< SysCallCaller > obj;
#endif

    obj.Foo();
}

, . .

0

Source: https://habr.com/ru/post/1524227/


All Articles