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

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

本文关键字:外部 系统 基类 派生 依赖于 何测试 测试      更新时间:2023-10-16

我有一个类,它是一个外部类的子类,我对它没有任何控制权。外部类依赖于系统资源。例如

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()编写单元测试。使用组合代替继承不是一种选择,因为框架需要从这个基类派生类。

我正在使用C++和GoogleTest/Mock。但任何广义的解决方案都值得赞赏。

提前谢谢。

有两种方法。我称之为"稍微正确一点"的方式和"非常丑陋"的方式。


"更正确"的方式:

用一些可以部分模拟的附加层封装外部类函数。

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);
}

当您需要在测试中调用真正的基类方法时,请将WillOnce(Invoke...)与EXPECT_call一起使用。


"非常丑陋"的方式:

提供您自己的ExternalBase的UnitTest实现,并将其链接到您的测试。ExternalBase的这种"UnitTest"实现应该基于一些全局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);
}