*** 还没有被宣布(虽然它是)
*** 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
。
这是一个更大项目的一部分,但看起来是这个文件导致了问题。
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
。