1

我开始在 C++ 中进行单元测试,并试图找出最佳实践。然而,今天我在编写使用boost interprocess的代码时有点碰壁,特别是仅在标头中定义的 file_mapping 和 mapped_region。

我的一般问题是:如何根据仅在头文件中定义的代码(即 Boost 和 STL)来测试类?

示例:假设我创建了一个类似 MyClass.h 的类:

#pragma once

#include <stddef>

namespace boost { namespace interprocess {
class mapped_region;
}}

class MyClass
{
public:
    MyClass(mapped_region& mapped_region);
    std::size_t get_size() const;

private:
    boost::interprocess::mapped_region& mapped_region_;
}

MyClass.cpp 文件:

#include "MyClass.h"
#include <boost/interprocess/mapped_region.hpp>

using namespace boost::interprocess;

MyClass::MyClass(mapped_region& mapped_region)
: mapped_region_(mapped_region) {}

std::size_t MyClass::get_size() const
{
    return mapped_region_.get_size();
}

如何测试 MyClass::get_size()?由于 mapped_region 仅在头文件中实现,它将创建一个基本上独立于其他目标文件的目标文件(也就是不需要链接),因此不会创建假或模拟对象,因为它无法链接。

我能看到工作的唯一方法是在 .cpp 中使用 #ifdefs 并在 MyClass.cpp 中执行类似的操作:

#ifdef RUN_UNITTEST
#include "my_fake_mapped_region.h"
#else
#include <boost/interprocess/mapped_region.hpp>
#endif

但这似乎是一个可怕的黑客攻击,并通过测试感染了生产代码。

我想可以在测试代码中使用 boost,但这需要在磁盘上创建文件,从技术上讲,它不再是单元测试,而是集成测试?(对不起,如果我对术语有误)。

我真的很感激关于这个问题的一些见解。

4

1 回答 1

4

创建典型抽象层的方法是将有问题的库包装在一个非常薄的层后面,您将其注入到需要它的对象的构造函数中。您已经明白,包装每个 boost 函数会将使用 boost 变成使用困难的非标准包装器。

正如您所发现的,您不能简单地从库中继承接口,因为声明包含实现,因为它是给您带来问题的实现。

诀窍是认识到您不必包装每个提升模板。你只需要包装那些给你“难以设置”和“难以测试”的问题。 boost::interprocess有资格作为那些难以测试的问题之一,所以它值得一个包装器。

请记住,您不应该在这里尝试测试提升。您的单元测试不(也不应该)关心它是否设置了真实的内存映射或调用了假的,只要调用似乎有效,以便您的测试可以继续。您也不需要测试您创建的包装器,只要它们非常薄,您可以轻松地验证它们不包含任何逻辑。例如,我不会费心测试该MyMemoryRegionWrapper::get_size()方法,因为目视检查表明它只是返回返回值。

于 2013-05-16T19:09:14.260 回答