如何测试从依赖于外部系统的外部基础 class 派生的 classes

How to test classes that is derived from external base class which depends on external system

我有一个 class,它是我无法控制的外部 class 的子 class。外部 class 取决于系统资源。例如

class MyClass : public ExternalBase // This class is from external framework and framework requires it to derive from this class.
{
    int doSomePrivateThing(int );
public: 

    virtual int DoSomething(int );
    virtual ~MyClass();
}

int MyClass::doSomePrivateThing(int )
{
    // do some private task
}

int MyClass::DoSomething(int n)
{
    // Do MyClass Specific task
    int k = doSomePrivateThing(n);
    return ExternalBase::DoSomething(k); // This function depends on external system resources.
                                         // Probably try to communicate with remote server 
                                         // or attempt access Storage or Display device etc.
}

MyClass::~MyClass()
{}

如何打破 MyClass 的依赖并为 MyClass::DoSomething() 编写单元测试。使用组合代替继承不是一种选择,因为框架需要 classes 从这个基础 class 派生。

我正在使用 C++ 和 GoogleTest/Mock。但是任何通用的解决方案都会受到赞赏。

提前致谢。

有两种方法。我称它们为 "a little more correct" 方式和 "very ugly" 方式。


"more correct"方式:

将外部 class 函数包含在可以部分模拟的附加层中。

class MyClass : public ExternalBase // This class is from external framework and framework requires it to derive from this class.
{
    int doSomePrivateThing(int );
public: 
    virtual void BaseDoSomething(int) { return ExternalBase::DoSomething(v); }
    virtual int DoSomething(int v);
    virtual ~MyClass();
};

int MyClass::DoSomething(int n)
{
    // Do MyClass Specific task
    int k = doSomePrivateThing(n);
    return BaseDoSomething(k); 
}

并以这种方式在 UT 中进行部分模拟:

class TestableMyClass : public MyClass
{
public:
    using MyClass::MyClass;
    MOCK_METHOD1(BaseDoSomething, int(int));
}; 

TEST(A,A)
{
    TestableMyClass objectUnderTest;
    EXPECT_CALL(objectUnderTest, BaseDoSomething(112));

    objectUnderTest.DoSomething(112);
}

当您还需要在测试中调用真正的基础 class 方法时 - 使用 WillOnce(Invoke...) 和 EXPECT_CALL。


"very ugly"方式:

提供您自己的 ExternalBase 的 UnitTest 实现,link 将其用于您的测试。 "UnitTest" ExternalBase 的实现应该基于一些全局 Mocks 对象。

ExternalBaseMock.hpp:

class ExternalBaseMock 
{
public:
    MOCK_METHOD1(DoSomething, int(int));
};
extern ExternalBaseMock  externalBaseMock;

ExternalBaseMock.cpp:

ExternalBaseMock  externalBaseMock;

int ExternalBase::DoSomething(int n)
{
    return externalBaseMock.DoSomething(n);
}

然后你的测试:

#include "ExternalBaseMock.hpp"

TEST(A,A)
{
    MyClass objectUnderTest;
    EXPECT_CALL(externalBaseMock, DoSomething(112));

    objectUnderTest.DoSomething(112);
}