GTest  交流 与经验总结 张长荣
关于我 <ul><li>张长荣 (coderzh) </li></ul><ul><li>博客: http://www.cnblogs.com/coderzh </li></ul><ul><li>参与项目: </li></ul><ul><ul><...
交 流 <ul><li>从  GTest  说起 </li></ul><ul><li>经验分享 </li></ul><ul><li>讨论交流 </li></ul>
GTest  缘分 <ul><li>Google 工程师 </li></ul><ul><li>技术交流 </li></ul><ul><li>留下印象 </li></ul>
GTest  缘分 <ul><li>自制单元测试框架: CppTestFramework </li></ul>分享:不要重复造轮子
GTest  缘分 <ul><li>分享:不喜欢偷懒的测试不是好开发 </li></ul>懒
GTest  缘分 <ul><li>测试框架经常有 BUG 要改 </li></ul><ul><li>用的不爽,想加个功能 </li></ul>分享: 不要让测试工作停下来,把框架维护的事情交给别人。
GTest  缘分 <ul><li>发现 Google Test 是个好东西 </li></ul>
GTest  缘分 <ul><li>使用 Google Test 的理由: </li></ul><ul><ul><li>简单 </li></ul></ul><ul><ul><li>好用 </li></ul></ul><ul><ul><li>优秀...
《玩转 GTest 》 zhanyong.wan from Google
《玩转 GTest 》 <ul><li>分享: </li></ul><ul><li>只要你想, </li></ul><ul><li>没有什么不可能。 </li></ul>
开始说 Gtest <ul><li>单元测试框架: CppUnit, NUnit, JUnit, LuaUnit,PhpUnit…… </li></ul><ul><li>Google C++ Testing Framework (gtest) ...
GTest 的特点 (1) <ul><li>跨平台: Linux, Mac OS, Windows... </li></ul><ul><li>支持 Nonfatal 断言 (EXPECT_*) </li></ul><ul><li>支持定制断言失...
GTest 的特点 (2) <ul><li>自动检测测试案例,不需要自己指定。 </li></ul><ul><li>轻松扩展断言宏 ( EXPECT_PRED* ) </li></ul><ul><li>支持 Death Tests </li><...
GTest 的特点 (3) <ul><li>使用简单: </li></ul><ul><ul><li>引用头文件 </li></ul></ul><ul><ul><li>引用 gtest.lib </li></ul></ul><ul><ul><li...
GTest  示例 <ul><li>#include <gtest/gtest.h> </li></ul><ul><li>TEST (FooTest, HandleNoneZeroInput) </li></ul><ul><li>{ </li>...
XUnit <ul><li>Test case </li></ul><ul><li>Test fixtures </li></ul><ul><li>Test suites </li></ul><ul><li>Test execution </l...
XUnit  基础 分享:测试代码尽量简洁、清晰。
XUnit  基础 <ul><li>import unittest </li></ul><ul><li>class TestFoo(unittest.TestCase): </li></ul><ul><li>def  setUp (self):...
XUnit  基础 <ul><li>[TestFixture] </li></ul><ul><li>public class FooTest { </li></ul><ul><li>[SetUp] </li></ul><ul><li>publi...
XUnit  基础 <ul><li>class FooTest:public testing::Test { </li></ul><ul><li>protected: </li></ul><ul><li>virtual void  SetUp(...
XUnit  基础 <ul><li>Test Fixture : </li></ul><ul><ul><li>Fresh Fixture </li></ul></ul><ul><ul><li>Shared Fixture </li></ul><...
XUnit  基础 <ul><li>class FooTest : public testing::Test  </li></ul><ul><li>{ </li></ul><ul><li>protected: </li></ul><ul><li...
GTest  全局 Setup/TearDown <ul><li>class FooEnvironment : public testing::Environment { </li></ul><ul><li>public: </li></ul>...
GTest  全局 Setup/TearDown <ul><li>int _tmain(int argc, _TCHAR* argv[])  </li></ul><ul><li>{ </li></ul><ul><li>testing::AddG...
Setup 异常机制 <ul><li>发生  Fatal Failure  后, </li></ul><ul><li>Global SetUp  -  直接退出,不执行任何案例 </li></ul><ul><li>SetUpTestCase  ...
XUnit  基础  -  断言 <ul><li>EXPECT_* </li></ul><ul><ul><li>EXPECT_EQ </li></ul></ul><ul><ul><li>EXPECT_TRUE </li></ul></ul><u...
XUnit  基础  -  断言 <ul><li>EXPECT_PRED_* / ASSERT_PRED_* </li></ul><ul><ul><li>自定义断言 </li></ul></ul><ul><ul><li>所有类型的断言实现的基础...
XUnit  基础  -  断言 <ul><li>TEST(FooTest, HandleFail) </li></ul><ul><li>{ </li></ul><ul><li>int m = 3; </li></ul><ul><li>int ...
XUnit  基础  -  断言 <ul><li>testing::AssertionResult  AssertFoo (const char* m_expr, const char* n_expr, const char* k_expr, ...
XUnit  基础  -  断言 <ul><li>... </li></ul><ul><li>#define  EXPECT_LE (val1, val2)  </li></ul><ul><li>#define  EXPECT_LT (val1...
XUnit  基础  -  断言 <ul><li>#define GTEST_IMPL_CMP_HELPER_(op_name, op) </li></ul><ul><li>template <typename T1, typename T2>...
XUnit  基础  -  断言 <ul><li>ASSERT_*  和  EXPECT_*  区别 </li></ul><ul><li>#define GTEST_FATAL_FAILURE_(message)  </li></ul><ul>...
XUnit  基础  -  断言 <ul><li>ASSERT_*  </li></ul><ul><ul><li>只是当前函数返回,并非测试案例返回。 </li></ul></ul><ul><ul><li>所在函数的返回值必须为 void 。 ...
GTest -  参数化测试 <ul><li>参数化测试(数据驱动测试) </li></ul>bool  IsPrime (int  n ) { ... } -1 0 1 2 13 99 ...
GTest -  参数化测试 <ul><li>可能,我们会这样写: </li></ul>TEST(IsPrimeTest, TestAll) { EXPECT_FALSE( IsPrime(-1) ); EXPECT_FALSE( IsPrim...
GTest -  参数化测试 分享: 一个测试案例,理想情况下,只需要一个断言。
GTest -  参数化测试 <ul><li>这就是理想情况: </li></ul><ul><li>TEST_P (IsPrimeParamTest, TrueReturn) </li></ul><ul><li>{ </li></ul><ul>...
GTest -  参数化测试 <ul><li>class IsPrimeParamTest : public::testing:: TestWithParam<int> </li></ul><ul><li>{ </li></ul><ul><li...
GTest -  运行参数 <ul><li>系统环境变量 </li></ul><ul><li>命令行参数 </li></ul><ul><ul><li>--gtest_filter = *.* </li></ul></ul><ul><li>代码中...
GTest -  运行参数 <ul><li>--gtest_list_tests </li></ul><ul><li>--gtest_filter </li></ul><ul><li>--gtest_also_run_disabled_test...
小技巧
小技巧 <ul><li>获取当前测试案例名称: </li></ul><ul><li>const ::testing::TestInfo* const test_info = </li></ul><ul><li>::testing::UnitTe...
GTest <ul><li>GTest  就讲到这里, </li></ul><ul><li>下面说说我对测试开发的一些理解 </li></ul>
经验交流 <ul><li>分享:做 有用 的测试 </li></ul>最高原则
经验交流 <ul><li>分享: </li></ul><ul><li>测试案例执行的次数越多,价值越大! </li></ul>
经验交流 <ul><li>分享: </li></ul><ul><li>稳定的测试案例才有效 </li></ul>
经验交流 <ul><li>正确理解  Mock: </li></ul><ul><ul><li>Dummy Object </li></ul></ul><ul><ul><li>Test Stub </li></ul></ul><ul><ul><l...
Google Mock <ul><li>TEST(PainterTest, CanDrawSomething) { </li></ul><ul><li>MockTurtle turtle;  </li></ul><ul><li>EXPECT_C...
BDD <ul><li>BDD (Behavior Driven Development) </li></ul>As  a [X]  I  want [Y]  so  that [Z] Given  some initial context  ...
BDD <ul><li>一个例子: </li></ul>Given  I am not logged in When  I log in as Morgan with a password SecretPassw0rd Then  I shou...
BDD <ul><li>using NBehave.Narrator.Framework; </li></ul><ul><li>using NBehave.Spec.NUnit; </li></ul><ul><li>[ActionSteps] ...
我的实践 <ul><li>TEST_F(NormalUpdateTest, OnlineUpdateFlow) </li></ul><ul><li>{ </li></ul><ul><li>ASSERT_TRUE(Delete(TheFile(L...
Principles <ul><li>Write the Tests First </li></ul><ul><li>Design for Testability </li></ul><ul><li>Use the Front Door Fir...
Principles <ul><li>Minimize Untestable Code </li></ul><ul><li>Keep Test Logic Out of Production Code </li></ul><ul><li>Ver...
做有用的测试! 谢谢大家
Upcoming SlideShare
Loading in...5
×

GTest交流与经验总结

21,653

Published on

Published in: Technology
1 Comment
13 Likes
Statistics
Notes
No Downloads
Views
Total Views
21,653
On Slideshare
0
From Embeds
0
Number of Embeds
7
Actions
Shares
0
Downloads
160
Comments
1
Likes
13
Embeds 0
No embeds

No notes for slide

GTest交流与经验总结

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

    Clipping is a handy way to collect important slides you want to go back to later.

×