C++ 被测试类的模拟依赖关系
我想测试一些编写用于在VisualStudio本机单元测试项目中的嵌入式处理器上运行的代码 TestMe类有几种方法可以很好地进行测试,但Foo和Bar类直接访问仅在嵌入式处理器上可用的内存映射寄存器C++ 被测试类的模拟依赖关系,c++,visual-studio,unit-testing,mocking,embedded,C++,Visual Studio,Unit Testing,Mocking,Embedded,我想测试一些编写用于在VisualStudio本机单元测试项目中的嵌入式处理器上运行的代码 TestMe类有几种方法可以很好地进行测试,但Foo和Bar类直接访问仅在嵌入式处理器上可用的内存映射寄存器 #pragma once #include "Foo.h" #include "Bar.h" class TestMe { public: TestMe(Foo& aFoo, Bar& aBar); ~TestMe(); float FooBar();
#pragma once
#include "Foo.h"
#include "Bar.h"
class TestMe
{
public:
TestMe(Foo& aFoo, Bar& aBar);
~TestMe();
float FooBar();
};
模仿这些对象以便测试TestMe类的最佳方法是什么
编辑:对我来说,最好的方法是尽可能少地干扰正在测试的软件 “最佳”总是主观的,但我喜欢使用模板进行此类模拟:
template <typename TFoo, typename TBar>
class TestMeImpl
{
public:
TestMeImpl(TFoo& aFoo, TBar& aBar);
~TestMeImpl();
float FooBar();
};
using TestMe = TestMeImpl<Foo, Bar>;
模板
类TestMeImpl
{
公众:
TestMeImpl(TFoo和aFoo、TBar和aBar);
~TestMeImpl();
float FooBar();
};
使用TestMe=TestMeImpl;
您可以针对
TestMeImpl
编写单元测试,但将TestMe
公开给您的用户。您的Foo
和Bar
通过引用传递给构造函数。
这有两种方法
我个人喜欢使用接口并利用多态对象
看起来是这样的:
class IFoo {
public:
virtual void someFunction() = 0;
};
class IBar {
public:
virtual void otherFunction() = 0;
};
class Foo : public IFoo {
....
void someFunction() {
}
};
class Bar : public IBar {
.....
void otherFunction() {
}
};
class TestMe {
public:
TestMe(IFoo& aFoo, IBar& aBar);
~TestMe();
float FooBar();
};
// test code (GMock example):
class MockFoo : public IFoo {
MOCK_METHOD(someFunction(), void());
};
class MockBar : public IBar {
MOCK_METHOD(otherFunction(), void());
};
TEST(TestMeTest, someTest)
{
MockBar bar;
MockFoo foo;
TestMe testMe(bar, foo);
EXPECT_CALL(bar, otherFunction());
EXPECT_EQ(0.2, testMe.FooBar());
}
这与使用模板基本相同。在这种情况下,使用了动态多态性。
在模板的情况下,你得到了一些类似的东西,所以有些人称之为静态多态性
这两种方法都有优缺点,您可以决定哪种方法最适合您。有一种解决方案,不只是为了测试目的而引入接口(: 链接时间替换 规则:
- Foo和Bar位于静态lib中(Foo和Bar可以有单独的lib)
- 不要将这些lib链接到testexec
- 创建将链接到test exec的模拟实现:
#pragma once
#include <gmock/gmock.h>
class FooMock
{
FooMock();
~FooMock();
MOCK_METHOD0(foo, void());
};
缺点是它不适用于多线程测试。
希望有帮助。根据嵌入式平台的大小和性能限制,引入接口仅用于单元测试可能不是一个好主意。对于小型系统,我倾向于使用表示某种处理器外围设备的类型别名类。我猜这也是“Foo”和“Bar”的含义在你的例子中代表 可以使用体系结构预定义为当前目标选择正确的类型别名
struct Uart1 {};
struct Uart1Mock {};
#ifdef __x86_64__
using SensorUart = Uart1Mock;
#else
using SensorUart = Uart1;
#endif
然后,应用程序代码只使用SensorUart,无论该类是依赖于实际串行端口还是仅使用标准io。您是将其放在单独的文件中还是放在TestMe.h中?我想如果我必须对许多类执行此操作,这将导致项目中出现大量与测试相关的代码。@Q-bertsuit:可能是一个单独的文件,因为它避免了这种情况Week
TestMeImpl
和Foo
/Bar
之间存在不必要的物理依赖关系。你说的“很多”是什么意思您现有的实现将成为模板,而唯一的额外代码是<代码>使用指令。因此,您将创建一个名为TestMeMy.Tpp和TestMe.h的新文件,它只包含“包含”和“使用”指令。这听起来很合理。问题很好,“包含”的标题不太好。请考虑重命名为“正在测试的类的模拟依赖项”。@MarekR谢谢,标题已更新
struct Uart1 {};
struct Uart1Mock {};
#ifdef __x86_64__
using SensorUart = Uart1Mock;
#else
using SensorUart = Uart1;
#endif