简体   繁体   English

C ++中的模拟和依赖注入

[英]Mocking and dependency injection in C++

I'm struggling to do unit testing with googlemock and dependency injection in C++. 我正在努力用C ++中的googlemock和依赖注入进行单元测试。 Mocks and dependency injection significantly ease code testing, but they heavily rely on virtual methods. 模拟和依赖注入显着简化了代码测试,但它们严重依赖于虚拟方法。 While classes in other languages use virtual methods by default, it is not the case of C++. 虽然其他语言中的类默认使用虚方法,但不是C ++的情况。 I'm using C++ to create a low-overhead performance measuring framework, so just making every single class inherit from an interface (w/ pure virtual methods) is not a desirable option. 我正在使用C ++来创建一个低开销的性能测量框架,所以只是让每个类继承一个接口(带有纯虚方法)都不是一个理想的选择。

Specifically, I'm having issues with testing classes that contains collections of objects such as the following one: 具体来说,我遇到了测试包含对象集合的类的问题,如下所示:

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_;
  // ...
};

To test this class I could do the following: 为了测试这个课程,我可以做以下事情:

class mock_event {
public:
  MOCK_METHOD0(read, void());
};

TEST(event_manager, test) {
  event_manager<mock_event> manager;
  // ...
}

But this won't work as I cannot set the expectations for the mock object, and mock objects from googlemock are not copyable (therefore, the call to std::transform fails to compile). 但这不起作用,因为我无法设置模拟对象的期望,并且来自googlemock的模拟对象不可复制(因此,对std::transform的调用无法编译)。

To solve this issue, when testing I could use pointers instead (eg, event_manager<mock_event*> ) and pass a factory to the event_manager constructor. 要解决此问题,在测试时我可以使用指针(例如, event_manager<mock_event*> )并将工厂传递给event_manager构造函数。 But, this won't compile because of calls such as e.read() (it should be e->read() instead when testing). 但是,由于诸如e.read()之类的调用,它将无法编译e->read()在测试时应该是e->read() )。

I could then use type traits to create a method that if given a reference just returned the reference, and if given a pointer, then dereference the pointer (eg, dereference(e).read() ). 然后,我可以使用类型特征来创建一个方法,如果给定引用只返回引用,并且如果给定指针,则取消引用指针(例如, dereference(e).read() )。 But, this just keeps adding tons of complexity and it doesn't look like a good solution (especially if needs to be done to test all classes that contain a collection of objects). 但是,这只是增加了大量的复杂性,它看起来不是一个好的解决方案(特别是如果需要进行测试包含对象集合的所有类)。

So, I was wondering whether there is a better solution to this, or it is just that mocking and dependency injection are not very suitable techniques for C++. 所以,我想知道是否有更好的解决方案,或者只是模拟和依赖注入不是非常适合C ++的技术。

I assume that you made appropriate performance measurements with a simple class emulating your standard use case before deciding that your application cannot tolerate going through the overhead of a pointer dereference to perform a virtual function call. 我假设您在使用一个模拟标准用例的简单类进行了适当的性能测量,然后才决定您的应用程序无法容忍通过指针取消引用的开销来执行虚函数调用。

If you read the gmock documentation, they have a "high performance mocking" section where they show how to use templates in production code to allow to mock non virtual functions. 如果您阅读gmock文档,他们会有一个“高性能模拟”部分,其中显示如何在生产代码中使用模板以允许模拟非虚拟函数。

I think that the first rule of code (production or test) is to keep the code as simple as possible, and so I am not convinced of changing production code with templates just to be able to test it (although on the other hand I am completely favorable to use TDD as a critique and guide to the design of my production code). 我认为代码(生产或测试)的第一条规则是保持代码尽可能简单,因此我不相信用模板更改生产代码只是为了能够测试它(尽管另一方面我是完全有利于使用TDD作为我的生产代码设计的批评和指南)。

As such, it looks like that your application needs another mocking framework, one that allows to perform mocking at link-time as opposed to run-time. 因此,看起来您的应用程序需要另一个模拟框架,允许在链接时执行模拟,而不是运行时。

Check out cpputest and cppumock ( https://cpputest.github.io/ ), that is able to mock both C free-standing functions and C++ non virtual methods. 查看cpputest和cppumock( https://cpputest.github.io/ ),它可以模拟C独立函数和C ++非虚拟方法。

The price to pay with cpputest/cppumock is that it requires more boilerplate than gmock, but it is very good. 使用cpputest / cppumock支付的价格是它需要比gmock更多的样板,但它非常好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM