Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question for branch coverage #39

Open
Chris7462 opened this issue Jul 19, 2022 · 0 comments
Open

Question for branch coverage #39

Chris7462 opened this issue Jul 19, 2022 · 0 comments

Comments

@Chris7462
Copy link

Chris7462 commented Jul 19, 2022

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant