【问题标题】:*** has not been declared (though it is)*** 尚未声明(尽管已声明)
【发布时间】:2022-01-21 19:56:32
【问题描述】:

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

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);
}

MockStreamImpl.hpp

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

帮助类避免代码重复:

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;

所有标题都有保护,所以我不确定循环依赖,但如果是,我将非常感谢您的解释。

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

我真的不明白问题出在哪里,如果有任何帮助,我将不胜感激。

我看到了很多相关的话题,但似乎都没有为我提供答案。

【问题讨论】:

  • #include "StreamTemplateImpl.cpp" 坏主意。许多工具(和人)会检测和编译这个cpp文件,导致程序链接时出现多个定义错误或其他问题。给文件一些其他扩展名,你就可以开始了。
  • @user4581301 同意,但这样我可以模拟模板方法。我没有看到任何其他解决方法如何使用 google mock 来做到这一点。好的我明白了。将其重命名为 .hpp
  • StreamImpl.hpp 包含 StreamTemplateImpl.cpp,其中包含 MockStreamImpl.hpp,其中包含 StreamImpl.hpp。绕着我们走。标头保护可以防止多重包含,但迟早会定义一些东西,但这不是因为它的标头已经启动但在被完全检查之前被另一个包含中断。

标签: c++ unit-testing templates circular-dependency gmock


【解决方案1】:

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

旁注:

StreamImpl 是个坏主意。

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

是非标准的,也是您遇到此问题的一部分。如果你使用标准

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

并将StreamImpl 转换为std::ostream 的子代,您可以传入MockStreamImpl 的重写,这也是std::ostream 的子代,并完全隐藏流中流的特化而不是写入流的函数。

附注到附注:模板operator&lt;&lt; 也不是一个好主意。大多数类型没有足够相似的规则可以被通用函数打印。当&lt;&lt; 模板尝试调用自身时,这会导致错误的输出或混淆的错误消息,因为它仍然是最佳匹配。

出了什么问题:

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

#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 受到包含保护的保护,我们得到

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 在定义之前是必需的。

【讨论】:

    猜你喜欢
    • 2011-01-22
    • 2017-05-18
    • 2017-07-05
    • 2019-09-19
    • 2012-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    相关资源
    最近更新 更多