Appearance
Appearance
代码覆盖率是一种度量方法,可以衡量你的代码有多少被执行过。它有助于测试用例开发:如果你认为测试用例已经写好,并且所有代码都经过测试,你可以检查这些测试用例是否真的覆盖了你的全部代码。
不过要注意,即使测试用例达到 100% 代码覆盖率并且所有测试用例都通过,也并不意味着你的代码就是完美的。代码覆盖率无法检测你是否遗漏了某些检查。
进行代码覆盖率测量需要 GCC。GCC 会对你的代码进行插桩,这意味着会在代码的重要位置放置计数器。GCC 4.1 及之后版本提供了支持插桩的 "--coverage" 选项。(对于 GCC 3.4 及之前版本,必须使用 "-fprofile-arcs -ftest-coverage" 选项。)
你还需要较新版本的 libtool,因为早期版本不会将 "--coverage" 选项传递给 gcc。已知 libtool 1.5.24 可以正常工作,而 1.5.22 已知存在问题。
步骤与 Development 页面中描述的相同,只是你还必须指定 "CFLAGS=--coverage" configure 选项:
~/wireshark$ ./autogen.sh~/wireshark$ ./configure CFLAGS=--coverage [options]~/wireshark$ make构建过程完成后,除了 .libs/ 目录下的 *.o object files 之外,还会创建 *.gcno 文件。现在你必须启动 wireshark 并运行测试用例,例如打开一个测试文件。退出 Wireshark 后,代码覆盖率结果将保存到多个 *.gcda 文件中。
~/wireshark$ ./wireshark假设我们想查看 epan/dissectors/packet-usb.c 中有多少代码被执行过。要检查这一点,必须使用 gcov 并指定 object file 和 source file:
~/wireshark$ cd epan/dissectors~/wireshark/epan/dissectors$ gcov -o .libs/libcleandissectors_la-packet-usb.o packet-usb.cFile '/usr/include/glib-2.0/glib/gutils.h'Lines executed:0.00% of 41/usr/include/glib-2.0/glib/gutils.h:creating 'gutils.h.gcov'File '/usr/include/glib-2.0/glib/gthread.h'Lines executed:0.00% of 4/usr/include/glib-2.0/glib/gthread.h:creating 'gthread.h.gcov'File '/usr/include/glib-2.0/glib/gstring.h'Lines executed:0.00% of 6/usr/include/glib-2.0/glib/gstring.h:creating 'gstring.h.gcov'File 'packet-usb.c'Lines executed:2.43% of 494packet-usb.c:creating 'packet-usb.c.gcov'上面显示的是摘要,详细结果可以在 *.gcov 文件中找到。下面这部分将显示 proto_reg_handoff_usb() 函数的所有行都执行了一次:
~/wireshark/epan/dissectors$ tail packet-usb.c.gcov -: 1583: -: 1584:void -: 1585:proto_reg_handoff_usb(void) 1: 1586:{ -: 1587: dissector_handle_t linux_usb_handle; -: 1588: 1: 1589: linux_usb_handle = create_dissector_handle(dissect_linux_usb, proto_usb); -: 1590: 1: 1591: dissector_add("wtap_encap", WTAP_ENCAP_USB_LINUX, linux_usb_handle); 1: 1592:}请注意,可以多次运行 wireshark:计数器会累加到现有的 *.gcda 文件中。如果你想清除计数器,只需删除 *.gcda 文件:
~/wireshark$ for i in $(find -iname '*\.gcda'); do rm $i; done当 *.gcda 文件准备好后,可以使用 lcov 生成漂亮的 HTML 报告。(在 Debian 下可用 "apt-get install lcov" 安装。)
第一步是将 *.gcda 文件转换为 lcov 可以理解的 *.info 文件。(截至 SVN revision 24015,存在一个问题:并非所有从 #line 1 "..." 类型行引用的源文件都能找到。解决方法是使用 "--no-checksum" 选项禁用行校验和生成。)
~/wireshark$ geninfo --compat-libtool --no-checksum .Found gcov version: 4.2.3Scanning . for .gcda files ...Found 1080 data files in .Processing ./gtk/gsm_map_stat.gcdaProcessing ./gtk/capture_if_dlg.gcdaProcessing ./gtk/hostlist_tr.gcda[...]Processing ./file.gcdaProcessing ./capture-pcap-util-unix.gcdaProcessing ./tap-dcerpcstat.gcdaFinished .info-file creation现在可以使用 genhtml 创建 HTML 输出。(截至 Wireshark 的 SVN revision 24015,需要给 genhtml 打一个小补丁,使其跳过不存在的源文件,见下文。)
~/wireshark$ mkdir lcov-output~/wireshark$ genhtml -o lcov-output/ $(find -iname '*\.gcda\.info')Reading data file ./gtk/range_utils.gcda.infoReading data file ./gtk/uat_gui.gcda.infoReading data file ./gtk/gui_utils.gcda.info[...]Reading data file ./tap-stats_tree.gcda.infoFound 1267 entries.Found common filename prefix "/home/nmarci/src/wireshark/wireshark"Writing .css and .png files.Generating output.Processing file capture-pcap-util.cProcessing file tap-bootpstat.cProcessing file g711.c[...]Processing file /usr/include/glib-2.0/glib/gthread.hWriting directory view page.Overall coverage rate: 24634 of 394629 lines (6.2%)如果你的构建过程以下列错误消息结束,则必须升级 libtool。已知版本 1.5.24 可以正常工作。注意:升级 libtool 不会修改 ./libtool(它可能仍然是旧版本),因此在升级 libtool 之后必须再次运行 "make distclean" 和 "./autogen.sh"。
/usr/bin/ld: .libs/wireshark: hidden symbol `__gcov_init' in /usr/lib/gcc/i486-linux-gnu/4.1.3/libgcov.a(_gcov.o) is referenced by DSO/usr/bin/ld: final link failed: Nonrepresentable section on outputcollect2: ld returned 1 exit statusmake[2]: *** [wireshark] Error 1make[2]: Leaving directory `/home/foo/wireshark'make[1]: *** [all-recursive] Error 1make[1]: Leaving directory `/home/foo/wireshark'make: *** [all] Error 2如果有源文件缺失,genhtml 会退出。解决方法是使用以下补丁:
--- /usr/bin/genhtml 2007-09-09 17:14:20.000000000 +0200+++ genhtml.modified 2008-01-05 13:47:00.000000000 +0100@@ -3165,6 +3165,15 @@ %count_data = %{$_[2]}; }+ if (!-f $source_filename) {+ write_source_prolog(*HTML_HANDLE);+ push (@result,+ write_source_line(HTML_HANDLE, 0,+ "(missing file)", 0, 0));+ write_source_epilog(*HTML_HANDLE);+ return (@result);+ }+ open(SOURCE_HANDLE, "<".$source_filename) or die("ERROR: cannot open $source_filename for reading!\n");于 2020-08-11 23:12:41 UTC 从 https://wiki.wireshark.org/Development/CodeCoverage 导入