Skip to content

Question for branch coverage #39

Open
@Chris7462

Description

@Chris7462

Hi, I have a question regarding branch coverage. I have turned on the branch coverage in the config file `/etc/lcovrc'

# Specify if branch coverage data should be collected and processed.
lcov_branch_coverage = 1

The sample code I'm testing does not have any if statement, so I was expecting the branch coverage to be 100%. But, the result is not what I expected.

image
image
For some reason, some lines that do not belong to the branches are treated as branch statements.

Here's the minimum working example.
Testing environment: Ubuntu 20.04.4 LTS, LCOV 1.14, and GCOV 9.04.

The sample_pkg_node subscribes to topic received_topic and publishes to topic sending_topic, both of them having std_msg::String type.

sample_pkg/src/sample_pkg_node.cpp

#include <ros/ros.h>
#include <std_msgs/String.h>

class SamplePkg
{
  public:
    SamplePkg(ros::NodeHandle& node) {
      subscriber_ = node.subscribe("received_topic", 100, &SamplePkg::sub_callback, this);
      publisher_ = node.advertise<std_msgs::String>("sending_topic", 100, true);
    };
    ~SamplePkg() = default;

  private:
    ros::Subscriber subscriber_;
    ros::Publisher publisher_;

    void sub_callback(const std_msgs::String::ConstPtr& input_msg) {
      std_msgs::String output_msg;
      output_msg.data = input_msg->data + " -- output";
      ROS_INFO_STREAM("Publish: " << output_msg.data);
      publisher_.publish(output_msg);
    }
};

int main(int argc, char** argv)
{
  ros::init(argc, argv, "sample_pkg_node");
  ros::NodeHandle node;

  SamplePkg sample_pkg(node);

  ros::spin();

  return 0;
}

The sample_pkg_test_node is the reverse of the sample_pkg_node, which subscribes to sending_topic and publishes to received_topic.

sample_pkg/test/sample_pkg_test.cpp

#include <ros/ros.h>
#include <gtest/gtest.h>
#include <std_msgs/String.h>

class SamplePkgTest: public ::testing::Test
{
  public:
    SamplePkgTest()
      : node_handle_(),
        publisher_(node_handle_.advertise<std_msgs::String>("received_topic", 5, true)),
        subscriber_(node_handle_.subscribe("sending_topic", 5, &SamplePkgTest::Callback, this)),
        message_received_(false)
    {
    }

    /*
     * This is necessary because it takes a while for the node under
     * test to start up.
     */
    void SetUp() override {
      while (!IsNodeReady()) {
        ros::spinOnce();
      }
    }

    void TearDown() override {
    }

    void Publish(std_msgs::String& msg) {
      publisher_.publish(msg);
    }

    /*
     * This is necessary because it takes time for messages from the
     * node under test to reach this node.
     */
    boost::shared_ptr<const std_msgs::String> WaitForMessage() {
      // The second parameter is a timeout duration.
      return ros::topic::waitForMessage<std_msgs::String>(
        subscriber_.getTopic(), node_handle_, ros::Duration(1));
    }

  private:
    bool message_received_;
    ros::NodeHandle node_handle_;
    ros::Publisher publisher_;
    ros::Subscriber subscriber_;

    /*
     * This callback is a no-op because we get the messages from the
     * node under test using WaitForMessage().
     */
    void Callback(const std_msgs::String& event) {
      message_received_ = true;
    }

    /*
     * See SetUp method.
     */
    bool IsNodeReady() {
      return (publisher_.getNumSubscribers() > 0) && (subscriber_.getNumPublishers() > 0);
    }
};

TEST_F(SamplePkgTest, SampleTest) {
  std_msgs::String msg;
  msg.data = "Test";
  Publish(msg);
  auto output = WaitForMessage();
  ASSERT_TRUE(output != NULL);
  EXPECT_EQ("Test -- output", output->data);
}

sample_pkg/test/main_test.cpp

#include <ros/ros.h>
#include <gtest/gtest.h>

int main(int argc, char** argv)
{
  testing::InitGoogleTest(&argc, argv);
  ros::init(argc, argv, "sample_pkg_test_node");

  return RUN_ALL_TESTS();
}

sample_pkg/test/sample_pkg_test.test

<?xml version="1.0"?>

<launch>
  <node name="sample_pkg_node" pkg="sample_pkg" type="sample_pkg_node"/>
  <test test-name="sample_pkg_test_node" pkg="sample_pkg" type="sample_pkg_test_node"/>
</launch>

I have followed the README to setup the CMakeLists.txt as well as the package.xml.

sample_pkg/CMakeLists.txt

cmake_minimum_required(VERSION 3.0.2)
project(sample_pkg)

find_package(catkin REQUIRED COMPONENTS
  roscpp
  std_msgs
)

catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES sample_pkg
  CATKIN_DEPENDS roscpp std_msgs
#  DEPENDS system_lib
)

if(CATKIN_ENABLE_TESTING AND ENABLE_COVERAGE_TESTING)
  find_package(code_coverage REQUIRED)
  # Add compiler flags for coverage instrumentation before defining any targets
  APPEND_COVERAGE_COMPILER_FLAGS()
endif()

include_directories(
  #include
  ${catkin_INCLUDE_DIRS}
)

add_executable(${PROJECT_NAME}_node
  src/sample_pkg_node.cpp
)

target_link_libraries(${PROJECT_NAME}_node
  ${catkin_LIBRARIES}
)

if(CATKIN_ENABLE_TESTING)
  find_package(rostest REQUIRED)

  add_rostest_gtest(sample_pkg_test_node
    test/sample_pkg_test.test
    test/sample_pkg_test.cpp
    test/main_test.cpp
  )

  target_link_libraries(sample_pkg_test_node
    ${catkin_LIBRARIES}
  )

  # Create a target ${PROJECT_NAME}_coverage_report
  if(ENABLE_COVERAGE_TESTING)
    set(COVERAGE_EXCLUDES "*/${PROJECT_NAME}/test*" "*/${PROJECT_NAME}/other_dir_i_dont_care_about*")
    add_code_coverage(
      NAME ${PROJECT_NAME}_coverage_report
      DEPENDENCIES tests
    )
  endif()
endif()

sample_pkg/package.xml

<?xml version="1.0"?>
<package format="2">
  <name>sample_pkg</name>
  <version>0.0.0</version>
  <description>The sample_pkg package</description>

  <maintainer email="[email protected]">yi-chen</maintainer>

  <license>TODO</license>

  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>std_msgs</build_depend>
  <build_export_depend>roscpp</build_export_depend>
  <build_export_depend>std_msgs</build_export_depend>
  <exec_depend>roscpp</exec_depend>
  <exec_depend>std_msgs</exec_depend>

  <test_depend>rostest</test_depend>
  <test_depend>code_coverage</test_depend>

  <!-- The export tag contains other, unspecified, tags -->
  <export>
    <!-- Other tools can request additional information be placed here -->

  </export>
</package>

Then, the package is built by the following commands:

  catkin config --cmake-args -DENABLE_COVERAGE_TESTING=ON -DCMAKE_BUILD_TYPE=Debug
  catkin build sample_pkg
  catkin build sample_pkg -v --no-deps --catkin-make-args sample_pkg_coverage_report 

I don't know which part I was doing it wrong. Any insight would be appreciated. Thank you.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions