我想测试一些编写为在Visual Studio本机单元测试项目中的嵌入式处理器上运行的代码。
TestMe类有几种方法可以很好地进行测试,但是Foo和Bar类可以直接访问仅在嵌入式处理器上可用的内存映射寄存器。
#pragma once
#include "Foo.h"
#include "Bar.h"
class TestMe
{
public:
TestMe(Foo& aFoo, Bar& aBar);
~TestMe();
float FooBar();
};
模拟这些对象以便测试TestMe类的最佳方法是什么?
编辑:对我而言,最好的方法是尽可能少地干扰正在测试的软件。
答案 0 :(得分:4)
“最佳”始终是主观的,但我喜欢使用模板来进行这种模拟:
template <typename TFoo, typename TBar>
class TestMeImpl
{
public:
TestMeImpl(TFoo& aFoo, TBar& aBar);
~TestMeImpl();
float FooBar();
};
using TestMe = TestMeImpl<Foo, Bar>;
您将针对TestMeImpl
编写单元测试,但向用户公开TestMe
。
答案 1 :(得分:0)
您的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());
}
这与使用模板基本相同。在这种情况下,使用动态多态性。 如果使用模板,您会得到类似的东西,因此有人将其称为静态多态。
这两种方法各有利弊,由您决定哪种方法最好。
答案 2 :(得分:0)
有一种解决方案,不只出于测试目的引入接口(: 链接时间替换。
规则:
Hpp文件:
#pragma once
#include <gmock/gmock.h>
class FooMock
{
FooMock();
~FooMock();
MOCK_METHOD0(foo, void());
};
Cpp文件:
#include "Foo.hpp"
#include "FooMock.hpp"
namespace
{
FooMock* fooMock;
}
FooMock::FooMock()
{
assert(!fooMock);
fooMock = this;
}
FooMock::~FooMock()
{
fooMock = nullptr;
}
// Implement real Foo::foo
void Foo::foo()
{
// call FooMock::foo
fooMock->foo();
}
缺点是它不适用于多线程测试。 希望对您有所帮助。
答案 3 :(得分:0)
根据嵌入式平台的大小和性能限制,仅出于单元测试的目的而引入接口可能是一个坏主意。对于小型系统,我更喜欢使用类型别名类的方法,该类代表了某种处理器外围设备。我猜这也是您示例中的“ Foo”和“ Bar”所代表的。
可以使用体系结构预定义来选择当前目标的正确类型别名
struct Uart1 {};
struct Uart1Mock {};
#ifdef __x86_64__
using SensorUart = Uart1Mock;
#else
using SensorUart = Uart1;
#endif
然后,无论该类是依赖于实际的串行端口还是仅使用标准io,应用程序代码都将仅使用SensorUart。