*** 还没有被宣布(虽然它是)

*** has not been declared (though it is)

这是一个更大项目的一部分,但看起来是这个文件导致了问题。

StreamImpl.hpp

class StreamImpl {
...
    template <typename Type>
    StreamImpl &operator<<(T &&out) noexcept;
...
};

#include "StreamTemplateImpl.cpp"

StreamTemplateImpl.cpp

// Templates implementation needed for test purposes
#include "StreamImpl.hpp"
#include "MockStreamImpl.hpp"

using ::utils::Dispatcher;
using ::mock::MockStreamImpl; // Error here

template <typename Type>
StreamImpl &operator<<(T &&out) noexcept
{
    return Dispatcher<MockStreamImpl>::Instance().Get()->OutOperator(out);
}

模拟StreamImpl.hpp

#include "StreamImpl.hpp"
namespace mock {
using ::StreamImpl;
class MockStreamImpl {
   MOCK_METHOD(...); // Gmock methods
};
}  // namespace mock

帮助class避免代码重复:

Fixture.hpp

#include "MockStreamImpl.hpp"

namespace fixture {
using ::mock::MockStreamImpl;
using ::utils::Dispatcher;
using ::testing::Test;

class UtStream : public Test {
   // Class for setting up mocks and common test data which is used as fixture in tests
   
    StreamImpl kDefaultStream_{};
}
}  // namespace fixture

和带有测试用例的文件,它使用 StreamImpl 模拟:

Tests.cpp

#include "Fixture.hpp"
... // Test cases

CMakeLists.txt

add_unit_test(
    TEST_NAME
        test_unit
    TEST_SOURCES
        unit_test_source_file.cpp
        ${SOURCES}/file_to_test.cpp
        ${MOCKS}/fake_stream_impl.cpp // source file with fake StreamImpl functions  implementations which redirects to mocks
    INCLUDE_DIRS
        ${INCLUDES}
        ${MOCKS}
        ${UTILS}
        ${FAKE_STREAM_IMPL_TEMPLATES} 
    LIBS
        gmock
        gtest
        gtest_main
)

当我尝试编译这个时,我得到了

In file included from /path/src/StreamImpl.hpp:281:0,
                 from /path/test/unit/mocks/MockStreamImpl.hpp:23,
                 from /path/test/unit/mocks/Fixture.hpp:24,
                 from /path/test/unit/unit_test_source_file.cpp:23:                                                                                                       
    /path/test/unit/mocks/fake_templates/StreamTemplateImpl.cpp:25:18: error: '::mock' has not been declared                                                     
     using ::mock::MockStreamImpl;

所有 headers 都有守卫,所以我不确定循环依赖,但如果是,我将非常感谢您的解释。

此外,当我在没有 Fixture.hpp 的情况下编译它时(Fixture.hpp 内容被合并到 unit_test_source_file.cpp 中)所有构建都完美。

我真的不明白问题出在哪里,非常感谢您的帮助。

我看到了很多相关主题,但似乎没有一个包含适合我的答案。

您遇到了体系结构问题,您在一个不好的地方抽象了不同类型的流,这不容易理清。模拟接口与被测代码过于紧密地交织在一起。您可以解决这个问题,但最好停下来仔细考虑您想要测试的内容。

边注排序:

StreamImpl 是个坏主意。

StreamImpl& operator<<(T &&out) noexcept;

是 non-standard 并且是您遇到此问题的部分原因。如果你使用标准

std::ostream & operator<<(std::ostream & strm,  T &&out) noexcept;

并将 StreamImpl 变成 std::ostream 的 child 你可以传入 MockStreamImpl 的 re-write 这也是一个 child std::ostream 并完全隐藏流内部流的特化而不是写入流的函数。

旁注的旁注:模板 operator<< 也不是一个好主意。大多数类型没有 similar-enough 规则可由通用函数打印。当 << 模板尝试调用自身时,这会导致愚蠢的输出或混乱的错误消息,因为它仍然是最佳匹配。

出了什么问题:

如果我们遵循包含并执行替换,我们可以看到编译器看到的内容:

#include "MockStreamImpl.hpp"

namespace fixture {
using ::mock::MockStreamImpl;
using ::utils::Dispatcher;
using ::testing::Test;

class UtStream : public Test {
   // Class for setting up mocks and common test data which is used as fixture in tests
   
    StreamImpl kDefaultStream_{};
}
}  // namespace fixture

导致

#include "StreamImpl.hpp"
namespace mock {
using ::StreamImpl;
class MockStreamImpl {
   MOCK_METHOD(...); // Gmock methods
};
}  // namespace mock
namespace fixture {
using ::mock::MockStreamImpl;
using ::utils::Dispatcher;
using ::testing::Test;

class UtStream : public Test {
   // Class for setting up mocks and common test data which is used as fixture in tests
   
    StreamImpl kDefaultStream_{};
}
}  // namespace fixture

然后到

class StreamImpl {
...
    template <typename Type>
    StreamImpl &operator<<(T &&out) noexcept;
...
};

#include "StreamTemplateImpl.cpp"

namespace mock {
using ::StreamImpl;
class MockStreamImpl {
   MOCK_METHOD(...); // Gmock methods
};
}  // namespace mock
namespace fixture {
using ::mock::MockStreamImpl;
using ::utils::Dispatcher;
using ::testing::Test;

class UtStream : public Test {
   // Class for setting up mocks and common test data which is used as fixture in tests
   
    StreamImpl kDefaultStream_{};
}
}  // namespace fixture

然后,打哈欠,

class StreamImpl {
...
    template <typename Type>
    StreamImpl &operator<<(T &&out) noexcept;
...
};

// Templates implementation needed for test purposes
#include "StreamImpl.hpp"
#include "MockStreamImpl.hpp"

using ::utils::Dispatcher;
using ::mock::MockStreamImpl; // Error here

template <typename Type>
StreamImpl &operator<<(T &&out) noexcept
{
    return Dispatcher<MockStreamImpl>::Instance().Get()->OutOperator(out);
}
namespace mock {
using ::StreamImpl;
class MockStreamImpl {
   MOCK_METHOD(...); // Gmock methods
};
}  // namespace mock
namespace fixture {
using ::mock::MockStreamImpl;
using ::utils::Dispatcher;
using ::testing::Test;

class UtStream : public Test {
   // Class for setting up mocks and common test data which is used as fixture in tests
   
    StreamImpl kDefaultStream_{};
}
}  // namespace fixture

并且由于 StreamImpl.hpp 和 MockStreamImpl.hpp 受到 include guards 的保护,我们得到

class StreamImpl {
...
    template <typename Type>
    StreamImpl &operator<<(T &&out) noexcept;
...
};

// Templates implementation needed for test purposes

using ::utils::Dispatcher;
using ::mock::MockStreamImpl; // Error here

template <typename Type>
StreamImpl &operator<<(T &&out) noexcept
{
    return Dispatcher<MockStreamImpl>::Instance().Get()->OutOperator(out);
}
namespace mock { //because mock isn't found by the compiler until here
using ::StreamImpl;
class MockStreamImpl {
   MOCK_METHOD(...); // Gmock methods
};
}  // namespace mock
namespace fixture {
using ::mock::MockStreamImpl;
using ::utils::Dispatcher;
using ::testing::Test;

class UtStream : public Test {
   // Class for setting up mocks and common test data which is used as fixture in tests
   
    StreamImpl kDefaultStream_{};
}
}  // namespace fixture

我们可以看到在定义之前需要 MockStreamImpl