• Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
No Downloads

Views

Total Views
21,043
On Slideshare
0
From Embeds
0
Number of Embeds
6

Actions

Shares
Downloads
156
Comments
1
Likes
13

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. GTest 交流 与经验总结 张长荣
  • 2. 关于我
    • 张长荣 (coderzh)
    • 博客: http://www.cnblogs.com/coderzh
    • 参与项目:
      • 金山 WPS
      • 金山毒霸
      • 月影传说 Online
    • 工作内容:
      • 测试平台、测试工具、模块 ( 接口 ) 测试、性能测试、安全性测试……
  • 3. 交 流
    • 从 GTest 说起
    • 经验分享
    • 讨论交流
  • 4. GTest 缘分
    • Google 工程师
    • 技术交流
    • 留下印象
  • 5. GTest 缘分
    • 自制单元测试框架: CppTestFramework
    分享:不要重复造轮子
  • 6. GTest 缘分
    • 分享:不喜欢偷懒的测试不是好开发
  • 7. GTest 缘分
    • 测试框架经常有 BUG 要改
    • 用的不爽,想加个功能
    分享: 不要让测试工作停下来,把框架维护的事情交给别人。
  • 8. GTest 缘分
    • 发现 Google Test 是个好东西
  • 9. GTest 缘分
    • 使用 Google Test 的理由:
      • 简单
      • 好用
      • 优秀的人在维护
  • 10. 《玩转 GTest 》 zhanyong.wan from Google
  • 11. 《玩转 GTest 》
    • 分享:
    • 只要你想,
    • 没有什么不可能。
  • 12. 开始说 Gtest
    • 单元测试框架: CppUnit, NUnit, JUnit, LuaUnit,PhpUnit……
    • Google C++ Testing Framework (gtest)
    XUnit
  • 13. GTest 的特点 (1)
    • 跨平台: Linux, Mac OS, Windows...
    • 支持 Nonfatal 断言 (EXPECT_*)
    • 支持定制断言失败时的输出 :
    • ASSERT_EQ(5, Foo(i)) << &quot; where i = &quot; << i;
  • 14. GTest 的特点 (2)
    • 自动检测测试案例,不需要自己指定。
    • 轻松扩展断言宏 ( EXPECT_PRED* )
    • 支持 Death Tests
    • 参数化测试
    • 丰富的命令行参数选项: ( --gtest_filter=*.* )
  • 15. GTest 的特点 (3)
    • 使用简单:
      • 引用头文件
      • 引用 gtest.lib
      • 主函数添加:
      • int _tmain(int argc, _TCHAR* argv[])
      • {
      • testing::InitGoogleTest(&argc, argv);
      • return RUN_ALL_TESTS();
      • }
      • TEST, TEST_F, TEST_P 编写测试案例
  • 16. GTest 示例
    • #include <gtest/gtest.h>
    • TEST (FooTest, HandleNoneZeroInput)
    • {
    • EXPECT_EQ (6, Foo(30, 18));
    • }
  • 17. XUnit
    • Test case
    • Test fixtures
    • Test suites
    • Test execution
    • Assertions
  • 18. XUnit 基础 分享:测试代码尽量简洁、清晰。
  • 19. XUnit 基础
    • import unittest
    • class TestFoo(unittest.TestCase):
    • def setUp (self):
    • pass
    • def tearDown (self):
    • pass
    • def TestCase1(self):
    • self.assertEqual(2, 2)
  • 20. XUnit 基础
    • [TestFixture]
    • public class FooTest {
    • [SetUp]
    • public void Init() { }
    • [TearDown]
    • public void UnInit() { }
    • [Test]
    • public void TestCase1() {
    • Assert.AreEqual(2, 2);
    • }
    • }
  • 21. XUnit 基础
    • class FooTest:public testing::Test {
    • protected:
    • virtual void SetUp() { }
    • virtual void TearDown() { }
    • };
    • TEST_F(FooTest, Test) {
    • EXPECT_EQ(1, 1);
    • }
  • 22. XUnit 基础
    • Test Fixture :
      • Fresh Fixture
      • Shared Fixture
    分享: 尽量避免 Slow Tests 。
  • 23. XUnit 基础
    • class FooTest : public testing::Test
    • {
    • protected:
    • static void SetUpTestCase () { }
    • static void TearDownTestCase () { }
    • };
  • 24. GTest 全局 Setup/TearDown
    • class FooEnvironment : public testing::Environment {
    • public:
    • virtual void SetUp () { }
    • virtual void TearDown () { }
    • };
  • 25. GTest 全局 Setup/TearDown
    • int _tmain(int argc, _TCHAR* argv[])
    • {
    • testing::AddGlobalTestEnvironment(new FooEnvironment);
    • testing::InitGoogleTest(&argc, argv);
    • return RUN_ALL_TESTS();
    • }
  • 26. Setup 异常机制
    • 发生 Fatal Failure 后,
    • Global SetUp - 直接退出,不执行任何案例
    • SetUpTestCase - 不影响后面的案例执行
    • Test Fixture SetUp - 当前案例退出,不执行
    HasFatalFailure()
  • 27. XUnit 基础 - 断言
    • EXPECT_*
      • EXPECT_EQ
      • EXPECT_TRUE
      • EXPECT_THROW
      • EXPECT_HRESULT_SUCCEEDED
      • ...
    • ASSERT_*
  • 28. XUnit 基础 - 断言
    • EXPECT_PRED_* / ASSERT_PRED_*
      • 自定义断言
      • 所有类型的断言实现的基础
    分享: 错误信息尽量详细和准确,尽量避免调试。
  • 29. XUnit 基础 - 断言
    • TEST(FooTest, HandleFail)
    • {
    • int m = 3;
    • int n = 6
    • EXPECT_PRED_FORMAT3 (AssertFoo, m, n, 2);
    • }
    • 结果:
    • error: m(3) 和 n(6) 的最大公约数应该是: 3 而不是: 2
  • 30. XUnit 基础 - 断言
    • testing::AssertionResult AssertFoo (const char* m_expr, const char* n_expr, const char* k_expr, int m, int n, int k) {
    • if (Foo(m, n) == k) return testing:: AssertionSuccess ();
    • testing::Message msg;
    • msg << m_expr << &quot;(&quot; << m << &quot;)&quot; << &quot; 和 &quot;
    • << n_expr << &quot;(&quot; << n << &quot;)&quot;
    • << &quot; 的最大公约数应该是: &quot; << Foo(m, n) << &quot; 而不是: &quot; << k_expr;
    • return testing:: AssertionFailure (msg);
    • }
  • 31. XUnit 基础 - 断言
    • ...
    • #define EXPECT_LE (val1, val2)
    • #define EXPECT_LT (val1, val2)
    • #define EXPECT_GE (val1, val2)
    • ...
    • EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
    • EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
    • EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
  • 32. XUnit 基础 - 断言
    • #define GTEST_IMPL_CMP_HELPER_(op_name, op)
    • template <typename T1, typename T2>
    • AssertionResult CmpHelper##op_name (const char* expr1, const char* expr2, const T1& val1, const T2& val2) {
    • if (val1 op val2) { return AssertionSuccess (); }
    • else {
    • }
    • }
    • return AssertionFailure(msg);
    • msg << &quot;Expected: (&quot; << expr1 << &quot;) &quot; #op &quot; (&quot; << expr2 << &quot;), actual: &quot; << FormatForComparisonFailureMessage(val1,val2) << &quot; vs &quot; << FormatForComparisonFailureMessage(val2, val1);
    • Message msg;
  • 33. XUnit 基础 - 断言
    • ASSERT_* 和 EXPECT_* 区别
    • #define GTEST_FATAL_FAILURE_(message)
    • return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure)
    • #define GTEST_NONFATAL_FAILURE_(message)
    • GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure)
  • 34. XUnit 基础 - 断言
    • ASSERT_*
      • 只是当前函数返回,并非测试案例返回。
      • 所在函数的返回值必须为 void 。
    int Func() // Wrong { ASSERT_EQ(1, 2); } TEST(TestFoo, TestFoo) { Func(); ASSERT_EQ(1, 0); } void Func() { ASSERT_EQ (1, 2); } TEST(TestFoo, TestFoo) { Func(); ASSERT_EQ (1, 0); }
  • 35. GTest - 参数化测试
    • 参数化测试(数据驱动测试)
    bool IsPrime (int n ) { ... } -1 0 1 2 13 99 ...
  • 36. GTest - 参数化测试
    • 可能,我们会这样写:
    TEST(IsPrimeTest, TestAll) { EXPECT_FALSE( IsPrime(-1) ); EXPECT_FALSE( IsPrime(0) ); EXPECT_FALSE( IsPrime(1) ); EXPECT_TRUE( IsPrime(2) ); EXPECT_TRUE( IsPrime(13) ); ... }
  • 37. GTest - 参数化测试 分享: 一个测试案例,理想情况下,只需要一个断言。
  • 38. GTest - 参数化测试
    • 这就是理想情况:
    • TEST_P (IsPrimeParamTest, TrueReturn)
    • {
    • int n = GetParam();
    • EXPECT_TRUE (IsPrime(n));
    • }
  • 39. GTest - 参数化测试
    • class IsPrimeParamTest : public::testing:: TestWithParam<int>
    • {
    • }
    • INSTANTIATE_TEST_CASE_P (TrueReturn, IsPrimeParamTest, testing::Values( 2,13,17,23 ));
  • 40. GTest - 运行参数
    • 系统环境变量
    • 命令行参数
      • --gtest_filter = *.*
    • 代码中指定 FLAG
      • testing::GTEST_FLAG(output) = &quot;xml:&quot;;
  • 41. GTest - 运行参数
    • --gtest_list_tests
    • --gtest_filter
    • --gtest_also_run_disabled_tests
    • --gtest_repeat=[COUNT]
    • --gtest_output=xml:
    • --gtest_break_on_failure
    • --gtest_throw_on_failure
  • 42. 小技巧
  • 43. 小技巧
    • 获取当前测试案例名称:
    • const ::testing::TestInfo* const test_info =
    • ::testing::UnitTest::GetInstance()->current_test_info() ;
    • printf(&quot;We are in test %s of test case %s.n&quot;,
    • test_info->name() , test_info->test_case_name() );
  • 44. GTest
    • GTest 就讲到这里,
    • 下面说说我对测试开发的一些理解
  • 45. 经验交流
    • 分享:做 有用 的测试
    最高原则
  • 46. 经验交流
    • 分享:
    • 测试案例执行的次数越多,价值越大!
  • 47. 经验交流
    • 分享:
    • 稳定的测试案例才有效
  • 48. 经验交流
    • 正确理解 Mock:
      • Dummy Object
      • Test Stub
      • Test Spy
      • Mock Object
      • Fake Object
  • 49. Google Mock
    • TEST(PainterTest, CanDrawSomething) {
    • MockTurtle turtle;
    • EXPECT_CALL(turtle, PenDown())
    • .Times(AtLeast(1));
    • Painter painter(&turtle);
    • EXPECT_TRUE(painter.DrawCircle(0, 0, 10));
    • }
  • 50. BDD
    • BDD (Behavior Driven Development)
    As a [X] I want [Y] so that [Z] Given some initial context When an event occurs, then ensure some outcomes. 故事模板 场景模板
  • 51. BDD
    • 一个例子:
    Given I am not logged in When I log in as Morgan with a password SecretPassw0rd Then I should see a message, &quot;Welcome, Morgan!&quot;
  • 52. BDD
    • using NBehave.Narrator.Framework;
    • using NBehave.Spec.NUnit;
    • [ActionSteps]
    • public class UserLogsInSuccessfully {
    • [ Given (&quot;I am not logged in&quot;)]
    • public void LogOut() { _currentPage.click(&quot;logout&quot;); }
    • [ When (&quot;I log in as $username with a password $password&quot;)]
    • publicvoid LogIn(string username, string password) { _currentPage.click(&quot;login&quot;); }
    • [ Then (&quot;I should see a message, &quot;$message&quot;&quot;)]
    • publicvoid CheckMessage(string message) {
    • _currentPage.ToString().ShouldContain(message);
    • }
    • }
  • 53. 我的实践
    • TEST_F(NormalUpdateTest, OnlineUpdateFlow)
    • {
    • ASSERT_TRUE(Delete(TheFile(L&quot;infoc.dat&quot;)->WhichIn(InstallDirectory)));
    • CallUpdate(WithCommandLine(L&quot;&quot;),
    • AndWithInternalParameter(L&quot;-online -custom&quot;));
    • EXPECT_TRUE(TheFile(L&quot;infoc.dat&quot;)->ExistsIn(InstallDirectory));
    • EXPECT_TRUE(TheFile(L&quot;infoc.dat&quot;)->WhichIn(InstallDirectory)->
    • HasTheSameCRCValueAs(TheFile(L&quot;infoc.dat&quot;)->
    • CRCValueInIndexDat()));
    • }
  • 54. Principles
    • Write the Tests First
    • Design for Testability
    • Use the Front Door First
    • Communicate Intent
    • Don’t Modify the SUT
    • Keep Tests Independent
    • Isolate the SUT
    • Minimize Test Overlap
  • 55. Principles
    • Minimize Untestable Code
    • Keep Test Logic Out of Production Code
    • Verify One Condition per Test
    • Test Conerns Separtely
    • Ensure Commensurate Effort and Responsibility
  • 56. 做有用的测试! 谢谢大家