【问题标题】:Build unit test for C with mocked dependencies using bazel使用 bazel 为具有模拟依赖项的 C 构建单元测试
【发布时间】:2019-05-25 19:14:27
【问题描述】:

我有一个尝试用 Bazel 构建的 C 代码库。该代码库包含使用 fff 库在 C 中生成函数模拟的单元测试。但实际的库并不重要,我对函数模拟的整个概念有疑问。

现在我有一个生成文件,我可以在其中链接并运行我的测试。当我构建一个测试时,我编译并链接被测库和测试源本身。该测试还为库的依赖项定义了模拟。链接后,模拟符号被解析为模拟实现,一切都按预期工作。但这样做的原因是我链接实际的依赖库,我链接测试源中定义的模拟符号。

主要问题是:我该如何使用 Bazel?在为cc_test 目标链接二进制文件时,Bazel 编译并链接所有传递依赖项。由于被测库依赖于(通过deps)符号的实际实现,因此这个真正的定义与模拟的定义一起链接,我自然会得到这个错误:multiple definition of XXX

例子:

cc_library(
  name = "a",
  # a.cc has the real version of "void some_function()".
  srcs = ["a.cc"],
  hdrs = ["a.h"],
)

# This test is working just fine.
cc_test(
  name = "a_test",
  srcs = ["a_test.cpp"],
  deps = [":a"],
)

cc_library(
  name = "b",
   # b.cc includes a.h and uses "void some_function()".
  srcs = ["b.cc"],
  hdrs = ["b.h"],
  deps = [":a"],
)

# This test has two definitions for "void some_function()":
# the real one and the mock one.
cc_test(
  name = "b_test",
  # b_test.cpp has the mock version of "void some_function()".
  srcs = ["b_test.cpp"],
  deps = [":b"],
)

我对 Bazel 并不完全陌生,但我也不是专家,在花了很多时间尝试之后我失败了。关于如何让它发挥作用的任何建议?

【问题讨论】:

  • 为什么要标记c++ 来回答C 问题?
  • 据我所知,整个项目是用 c++ 而不是 c。您使用后缀 cpp 以及 bazel 的 c++ 连接器(我认为他们没有用于 c 的连接器)。不知道是否可以使用 fff 但这是另一个问题。

标签: c bazel


【解决方案1】:

您的问题可能是一个非常基本的问题,与命名空间和/或扩展类有关。

c 根据定义没有命名空间,但可以以某种方式模拟它们:
https://stackoverflow.com/a/28535585/1019850

但由于您可能使用 c++ 而从不使用 c,因此可以直接使用命名空间。

具体的问题是你有两倍的相同函数,用命名空间a.some_function()b.some_function() 表示。

在 Bazel 中存在多种解决方法,我只发布了简短复制的 sn-ps,您必须在链接页面上阅读详细信息。

deps = [
    "@gtest//:main",
    "//lib:hello-greet",
],

链接:https://docs.bazel.build/versions/master/cpp-use-cases.html
那里的 sn-p 也用于测试,但我认为这与您的问题无关。

那么Bazel中存在工具链,这里是一个例子:

config_setting(
    name = "on_linux",
    constraint_values = [
        "@bazel_tools//platforms:linux",
    ],
)

config_setting(
    name = "on_windows",
    constraint_values = [
        "@bazel_tools//platforms:windows",
    ],
)

bar_binary(
    name = "myprog",
    srcs = ["mysrc.bar"],
    compiler = select({
        ":on_linux": "//bar_tools:barc_linux",
        ":on_windows": "//bar_tools:barc_windows",
    }),
)

链接:https://docs.bazel.build/versions/master/toolchains.html

由于我不是用 c 或 c++ 编程,通常我需要相当长的时间来挖掘足够的时间来发布解决方案,所以我必须在没有真正解决方案的情况下保留它,但我希望问题和方法解决它变得更清楚了。
我会先尝试第二个链接,在上面的第一个 sn-p 下方。

【讨论】:

  • 谢谢,但这不是我要解决的问题。是的,事实上,我确实使用 C,而不是 C++。我确实使用 C++ 库 GoogleTest 进行单元测试,但被测代码是纯 C。无论如何,问题是关于链接,而不是编译。
  • 为什么使用 cc 和 cpp 文件后缀?您的问题与这些文件有关。我的回答中推荐的方式从未提及编译,而是如何链接“deps”的不同方式
【解决方案2】:

我认为 Bazel 本身没有任何好的解决方案。对于 C++,Bazel 尝试创建一个简单明了的依赖管理系统来减少所有恶作剧,这可以在 C/C++ 编译/链接系统中完成。而且你的情况很不寻常。

我看到的唯一解决方案是使用weak symbols 将负担转移到链接器。您可以使用__attribute__((weak)) 来注释您的“正常”功能。应该在所有目标中选择“假”函数而不是“正常”函数,其中存在强大的函数符号(假函数)

【讨论】:

    猜你喜欢
    • 2023-03-13
    • 1970-01-01
    • 2016-02-19
    • 1970-01-01
    • 2018-03-18
    • 2017-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多