我正努力用googlemock和C中的依赖注入进行单元测试 . 模拟和依赖注入显着简化了代码测试,但它们严重依赖于虚拟方法 . 虽然其他语言中的类默认使用虚方法,但不是C的情况 . 我正在使用C来创建一个低开销的性能测量框架,所以只是让每个类继承一个接口(带有纯虚方法)都不是一个理想的选择 .
具体来说,我遇到了测试包含对象集合的类的问题,如下所示:
struct event_info { /* ... */ };
template<typename Event>
class event_manager {
public:
event_manager(const std::vector<event_info>& events) {
std::transform(begin(events), end(events),
std::back_inserter(events_),
[](const event_info& info) { return Event{info}; });
}
void read() {
for (auto& e : events_)
e.read();
}
// ...
private:
std::vector<Event> events_;
// ...
};
为了测试这个课,我可以做以下事情:
class mock_event {
public:
MOCK_METHOD0(read, void());
};
TEST(event_manager, test) {
event_manager<mock_event> manager;
// ...
}
但这不起作用,因为我无法设置模拟对象的期望,并且来自googlemock的模拟对象不可复制(因此,对 std::transform
的调用无法编译) .
为了解决这个问题,在测试时我可以使用指针(例如, event_manager<mock_event*>
)并将工厂传递给 event_manager
构造函数 . 但是,由于 e.read()
之类的调用(在测试时它应该是 e->read()
),因此无法编译 .
然后,我可以使用类型特征来创建一个方法,如果给定引用刚刚返回引用,并且如果给定指针,则取消引用指针(例如, dereference(e).read()
) . 但是,这只是增加了大量的复杂性,它看起来不是一个好的解决方案(特别是如果需要进行测试包含对象集合的所有类) .
所以,我想知道是否有更好的解决方案,或者只是模拟和依赖注入不是非常适合C的技术 .
1 回答
我假设您使用一个简单的类来模拟您的标准用例进行了适当的性能测量,然后再决定您的应用程序无法容忍通过指针取消引用的开销来执行虚函数调用 .
如果您阅读gmock文档,他们会有一个“高性能模拟”部分,其中显示如何在 生产环境 代码中使用模板以允许模拟非虚拟函数 .
我认为代码( 生产环境 或测试)的第一条规则是尽可能简化代码,因此我不相信用模板更改 生产环境 代码只是为了能够测试它(尽管另一方面我是完全有利于使用TDD作为我的 生产环境 代码设计的批评和指南) .
因此,看起来您的应用程序需要另一个模拟框架,允许在链接时执行模拟而不是运行时 .
查看cpputest和cppumock(https://cpputest.github.io/),它能够模拟C独立函数和C非虚拟方法 .
使用cpputest / cppumock支付的价格是它需要比gmock更多的样板,但它非常好 .