如何测试从依赖于外部系统的外部基础 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);
}
我有一个 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);
}