【GTEST使用一 官网】

官网:http://wiki.ros.org/gtest 翻译如下:

1. 获取gtest

 ros版使用 http://wiki.ros.org/ros_comm

2. Goolge Test

 GoolgeTest /gtest,c++语言的单元测试,官方文档 https://github.com/google/googletest,也可以参考http://www.ibm.com/developerworks/aix/library/au-googletestingframework.html
 这些网页给了一些细节步骤,写并且调用单元测试,包括在ROS的代码中

3. 代码结构

 按照惯例,如果你的包结构不复杂,建一个test的目录,并在test下写单元测试就够了。

4. 写单元测试

 一个基础的测试结果如下:

1 // Bring in my package’s API, which is what I’m testing
2 #include “foo/foo.h”
3 // Bring in gtest
4 #include <gtest/gtest.h>
5
6 // Declare a test
7 TEST(TestSuite, testCase1)
8 {
9 <test things here, calling EXPECT_* and/or ASSERT_* macros as needed>
10 }
11
12 // Declare another test
13 TEST(TestSuite, testCase2)
14 {
15 <test things here, calling EXPECT_* and/or ASSERT_* macros as needed>
16 }
17
18 // Run all the tests that were declared with TEST()
19 int main(int argc, char **argv){
20 ​testing::InitGoogleTest(&argc, argv);
​21 ​ros::init(argc, argv, “tester”);
​22 ​ros::NodeHandle nh; ​23 ​return RUN_ALL_TESTS()
23 return RUN_ALL_TESTS()
24 }

4.1. 测试命名惯例
每一个测试是一个test case,test case被组合到test suites里。需要合理的使用test suites。很多包可以用同一个test suites,但是如果有必要的话你可以使用多个。
test suites命名类似c++的驼峰式的类型定义
test case的命名方法都类似c++驼峰式的函数定义

5. 构建和执行tests

使用CMakeLists.txt构建的:

catkin_add_gtest(utest test/utest.cpp)

6. 测试输出

类似如下:

 [==========] Running 3 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 3 tests from MapServer
[ RUN      ] MapServer.loadValidPNG
[       OK ] MapServer.loadValidPNG
[ RUN      ] MapServer.loadValidBMP
[       OK ] MapServer.loadValidBMP
[ RUN      ] MapServer.loadInvalidFile
[       OK ] MapServer.loadInvalidFile
[----------] Global test environment tear-down
[==========] 3 tests from 1 test case ran.
[  PASSED  ] 3 tests.

执行完毕在test_results文件夹下输出一个xml,汇总了输出结果

7. 例子

7.1 函数调用

下面的例子是从math_utils包拿出来的。它可以你怎么test各种不同的函数。
EXCEPT_*的宏和ASSERT_*的宏的区别是,后者遇到失败的情况,直接退出程序。

#include "math_utils/MathExpression.h"
#include "math_utils/math_utils.h"
#include <gtest/gtest.h>

#define TEST_EXPRESSION(a) EXPECT_EQ((a), meval::EvaluateMathExpression(#a))

TEST(MathExpressions, operatorRecognition){
  EXPECT_TRUE(meval::ContainsOperators("+"));
  EXPECT_TRUE(meval::ContainsOperators("-"));
  EXPECT_TRUE(meval::ContainsOperators("/"));
  EXPECT_TRUE(meval::ContainsOperators("*"));
  EXPECT_FALSE(meval::ContainsOperators("1234567890qwertyuiop[]asdfghjkl;'zxcvbnm,._=?8")); 
}

TEST(MathExpressions, basicOperations){
EXPECT_EQ(5, meval::EvaluateMathExpression("2+3"));
EXPECT_EQ(5, meval::EvaluateMathExpression("2 + 3"));
EXPECT_EQ(10, meval::EvaluateMathExpression("20/2"));
EXPECT_EQ(-4, meval::EvaluateMathExpression("6 - 10"));
EXPECT_EQ(24, meval::EvaluateMathExpression("6 * 4"));
}

TEST(MathExpressions, complexOperations){
  TEST_EXPRESSION(((3 + 4) / 2.0) + 10);
  TEST_EXPRESSION(7 * (1 + 2 + 3 - 2 + 3.4) / 12.7);
  TEST_EXPRESSION((1 + 2 + 3) - (8.0 / 10)); 
}

TEST(MathExpressions, UnaryMinus){
  TEST_EXPRESSION(-5);
}

TEST(MathExpressions, badInput){
  //TODO - figure out what good error behavior is and test for it properly
  //EXPECT_EQ(0, meval::EvaluateMathExpression("4.1.3 - 4.1"));
  //EXPECT_EQ(0, meval::EvaluateMathExpression("4.1.3"));
}

TEST(MathUtils, basicOperations){
  EXPECT_EQ(math_utils::clamp<int>(-10, 10, 20), 10);
  EXPECT_EQ(math_utils::clamp<int>(15, 10, 20), 15);
  EXPECT_EQ(math_utils::clamp<int>(25, 10, 20), 20);
}

int main(int argc, char **argv){
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

7.2 处理异常

google 不使用异常,所以gtest不处理他们
如果你的testing代码抛异常,需要自己try catch,并且使用ADD_FAILURE或者FAIL等宏,ADD_FAILURE
另外注意,SUCCEED的宏是纯记录性质的,如果你想test中间的时候终止test程序,必须显示的return

7.3 持久化数据,使用test fixtures

通过创建test fixtures,你可以创建一个持久化的数据对象,具体是类继承testing::Test,测试的时候使用TEST_F这个宏定义。
一个最常见的场景是,当你在不同的test case中测试相同的一个函数,一些需要初始化的变量和条件冗长,且需要多次使用。
下面是一个例子:

#ifndef TALKER
#define TALKER

#include <ros/ros.h>
#include "geometry_msgs/Vector3.h"

class Talker{
    ros::NodeHandle nh;
    ros::Publisher pub;
public:
    Talker(); 
    void pubMsg(geometry_msgs::Vector3&& v);
    geometry_msgs::Vector3 add(const geometry_msgs::Vector3& a, const geometry_msgs::Vector3& b);
    geometry_msgs::Vector3 mult(const geometry_msgs::Vector3& a, const geometry_msgs::Vector3& b);
};

# endif // TALKER_H

如果我们想测试add和mult的时候,使用相同的参数,这时候就可以使用test fixture来初始化和销毁我们的变量

#include <gtest/gtest.h>
#include "talker/talker.h"

// helper function to create a geometry_msg::Vector3
auto createVec = [](double x, double y, double z) {
  geometry_msgs::Vector3 v;
  v.x = x;
  v.y = y;
  v.z = z;
  return v;
};

class TalkerFixture : public ::testing::Test {
  protected:
    geometry_msgs::Vector3 a;
    geometry_msgs::Vector3 b;
  
  // Setup
  TalkerTest() {
    a = createVec(1,2,3);
    b = createVec(2,2,2);
  }
};

TEST_F(TalkerFixture, TestAdder) {
  Talker talk;
  // a and b are inherited from TalkerTest
  geometry_msgs::Vector3 vec = talk.add(a,b);
  geometry_msgs::Vector3 ans = createVec(3,4,5);

  ASSERT_EQ(ans.x, vec.x) << "Talker add x's failed";
  ASSERT_EQ(ans.y, vec.y) << "Talker add y's failed";
  ASSERT_EQ(ans.z, vec.z) << "Talker add z's failed";
}

TEST_F(TalkerFixture, TestMult) {
  Talker talk;
  // a and b are inherited from TalkerTest
  geometry_msgs::Vector3 vec = talk.mult(a,b);
  geometry_msgs::Vector3 ans = createVec(2,4,6);

  ASSERT_EQ(ans.x, vec.x) << "Talker mult x's failed";
  ASSERT_EQ(ans.y, vec.y) << "Talker mult y's failed";
  ASSERT_EQ(ans.z, vec.z) << "Talker mult z's failed";
}

int main(int argc, char** argv) {
    ::testing::InitGoogleTest(&argc, argv);
    ros::init(argc, argv, "test_talker");
    ros::NodeHandle nh;
    return RUN_ALL_TESTS();
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值