如何使用Makefile合并unittest结果?

5 投票
3 回答
6161 浏览
提问于 2025-04-16 14:59

我想用一个Makefile来运行单个测试文件,或者把所有测试合在一起运行,或者生成一个覆盖率报告。

我对Makefile还不是很熟悉,所以我借用了一个并进行了修改。结果可以在这里找到。

问题是,使用make test命令时,它会一个接一个地运行每个测试,这样当测试很多时,很难看到哪些测试失败了,而且屏幕会滚动得很快。不过,我喜欢每个测试都在独立的进程中运行,这样它们之间不会互相干扰。

我的问题是:我能不能只用Makefile更好地合并结果,还是需要一个单独的脚本?你知道一些好的Makefile示例来运行测试吗?

(我只想使用Makefile + unittest + coverage,不想要其他依赖)

3 个回答

0

我有一个库目录,里面有几个子目录,每个子目录都有自己的单元测试。为了能一次性运行所有测试,我添加了以下测试目标:

test: $(addprefix test-,$(SUBDIRS))
test-%:
      $(MAKE) -k --directory=$* test

这挺不错的,因为它可以在每个子目录中运行测试,而且可以通过比如说 make test -j5 来分发运行。不过,它有个问题。理想情况下,我希望能在所有目录中运行测试,而不管某个目录里的测试是否失败。我还想在最后能总结一下失败的情况,更重要的是,如果有一个或多个测试失败,能返回一个非零的退出代码。上面的代码可以运行所有测试,但它不会打印总结,也不会返回非零的退出状态。

下面是一些更复杂的代码,它能实现我想要的功能。不过,这段代码看起来不是很优雅:

clean_test:
       rm -f testfailures
test: clean_test
       $(MAKE) $(addprefix test-,$(SUBDIRS))
       @echo "=== TEST SUMMARY ==="
       @if [ -f $(BUILD_DIR)/testfailures ]; then \
           echo "The following tests failed:"; \
           cat $(BUILD_DIR)/testfailures; \
           false; \
       else \
          echo "All tests passed."; \
       fi
test-%:
       $(MAKE) -k --directory=$* test || echo \
           "    $*" >> $(BUILD_DIR)/testfailures
8

另一种方法是使用unittest发现功能,这样可以把你所有的测试文件聚合到一起,一次性运行,比如在Makefile中。

 test:
    python -m unittest discover -p '*tests.py' -v

如果你觉得并行运行测试很重要,那就不要用unittest来运行测试,而是用nose或者pytest。这两个工具都有并行运行测试的选项。你应该可以在不修改测试代码的情况下做到这一点。

1

这里有一个简单的小技巧,你可以把它放到你的Makefile里,而不需要改动你的基础设施。

这个特殊的变量$?会保存上一个命令的执行结果。通过使用它,你可以检查每个测试的返回值。在下面的脚本中,我统计了失败的测试数量,并在运行结束时输出这个数字。如果你想的话,也可以在一个测试失败时立即退出,这样就不用向上滚动查看输出了。

failed=0 \
for i in $(TESTS); \
do \
  echo $$i; \
  PYTHONPATH=$(GAEPATH):. $(PYTHON) -m tests.`basename $$i .py` $(FLAGS); \
  if [ $? -ne 0 ] \
  then \
   $failed=$(($failed+1)) \
  fi \
done \
if [$failed -ne 0] \
then \
  echo $failed Tests Failed \
  exit $failed \
fi \

当然,还有更好、更稳妥的测试方法,但这个小技巧如果你需要的话也能用。我建议你最终把下面的bash脚本转成python,这样你只需要运行./run_tests.py就能执行所有的单元测试。因为python比bash更灵活,你可以更自由地解释和展示结果。根据你的需求,使用像unittest这样的单元测试框架可能会比自己写代码更好。

撰写回答