恐怖のFragile Tests問題

3,231 views

Published on

TDDカンファレンス 2012/4/6

0 Comments
7 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,231
On SlideShare
0
From Embeds
0
Number of Embeds
665
Actions
Shares
0
Downloads
15
Comments
0
Likes
7
Embeds 0
No embeds

No notes for slide

恐怖のFragile Tests問題

  1. 1. 恐怖のFragile  Tests問題 @goyoki2012/4/6  TDDカンファレンス
  2. 2. Fragile  Tests
  3. 3. t  -­‐  w  ad  a  先 生 ⻤⿁鬼畜な出題者によって TDD  Boot  Campで毎回犠牲者を⽣生む
  4. 4. TDDにおけるエントロピー問題
  5. 5. TEST(testHoge, InspectionFugaPiyo){ MotorStatus motorStatus(0, 0); MaintenanceData mtData; MaintenanceType mtType(createRegionID(EU)); setInitialData(mtData, mtType); InspectionFuga inspector; inspector.set(createMaintenanceInfo(mtData, mtType), motorStatus); …}TEST(testHoge, InspectionFugaFuga){ MotorStatus motorStatus(-1, 2); MaintenanceData mtData; MaintenanceType mtType(createRegionID(ASIA)); setInitialData(mtData, mtType); InspectionFuga inspector; inspector.set(createMaintenanceInfo(mtData, mtType), motorStatus); …}
  6. 6. TEST(testHoge, InspectionFugaHoge){ MotorStatus motorStatus(133, 232); MaintenanceData mtData; MaintenanceType mtType(createRegionID(JAPAN)); setInitialData(mtData, mtType); InspectionFuga inspector; inspector.set(createMaintenanceInfo(mtData, mtType), motorStatus); …}
  7. 7. TEST(testHoge, InspectionFugaHoge){ MotorStatus motorStatus(133, 232); MaintenanceData mtData; MaintenanceType mtType(createRegionID(JAPAN)); setInitialData(mtData, mtType); InspectionFuga inspector; inspector.set(createMaintenanceInfo(mtData, mtType), motorStatus); …} それなりの量量のコードを 何⼗十カ所もコピペして テストコードを書いたら?
  8. 8. Fragile  Tests テストと製品コードが 不不適切切な形で結合し⼩小さな変更更の度度に多くのテスト の修正が必要になる状態
  9. 9. 不不適切切な結合の要因隠蔽されるべき内部コードと結合 多数の重複コード 不不必要に多いコードの参照 状態を共有 副作⽤用に依存 複雑なSetUpやTearDown 保守性に劣劣るインターフェース リスクあるコードと結合
  10. 10. テストは 変更更をサポートしてくれるテストはリファクタリングを サポートしてくれる
  11. 11. はず。
  12. 12. しかしFragile  Tests の状態に陥ると
  13. 13. テストが製品コードの変更更を妨害する テストが テストの変更更を妨害する テストが リファクタリングの コストを悪化させる
  14. 14. テストの保守性を無視し、単純にRed  Green  Refactor のサイクルをまわして テストを⽣生み続けると…
  15. 15. テストの破棄 orF  r  a  g  i  l  e      T  e  s  t  s  問 題 モンスターとの死闘
  16. 16. Fragile  Testsから逃れるにはどうすればよいか
  17. 17. 継続的にテストの保守性を ⾼高める
  18. 18. TEST(FooTest,  Bar)  {                  MotorStatus  motorStatus(0,  0);                  MaintenanceData  mtData;                  MaintenanceType  mtType(createRegionID(EU));                  setIniDalData(mtData,  mtType);                  …                    InspecDonFuga  inspector;                  inspector.set(MaintenanceInfo(mtData,  mtType),  motorStatus);                  …  }  
  19. 19. 多数のプロダクトコードに依存TEST(FooTest,  Bar)  {                  MotorStatus  motorStatus(0,  0);                  MaintenanceData  mtData;                  MaintenanceType  mtType(createRegionID(EU));                  setIniDalData(mtData,  mtType);                  …                    InspecDonFuga  inspector;                  inspector.set(MaintenanceInfo(mtData,  mtType),  motorStatus);                  …   その他:}    変更リスクの高いコード  堅牢性の劣るコード
  20. 20. リスクあるコードはラッピングしたり 共通化したりして分離するTEST(FooTest,  Bar)  {                  InspecDonFuga  inspector  =  CreateInspecDonFuga(0,  EU);                                                                        …                                      inspector.set(MaintenanceInfo(mtData,  mtType),  motorStatus);                  …  }  
  21. 21. TEST_F(BuyerTest,  addSameStatus)  {                  Buyer  buyer;                  Customer  customer1("Taro",  "Yamada",  15,  2,  "HOGE|FUGA");                  customer1.addCategory(STATE_ACTIVE);                  Customer  customer2("Taro",  "Yamada",  15,  2,  "HOGE|FUGA|HOGEHOGE");                  customer2.addCategory(STATE_ACTIVE);                  ….                    buyer.add(customer1);                  buyer.add(customer2);                  ….                  EXPECT_EQ(0,  buyer.getSecDon());  }  
  22. 22. 重複するコードTEST_F(BuyerTest,  addSameStatus)  {                  Buyer  buyer;                  Customer  customer1("Taro",  "Yamada",  15,  2,  "HOGE|FUGA");                  customer1.addCategory(STATE_ACTIVE);                  Customer  customer2("Taro",  "Yamada",  15,  2,  "HOGE|FUGA|HOGEHOGE");                  customer2.addCategory(STATE_ACTIVE);                  ….                    buyer.add(customer1);                  buyer.add(customer2);                  ….                  EXPECT_EQ(0,  buyer.getSecDon());  }  
  23. 23. 共通化するTEST_F(BuyerTest,  addSameStatus)  {                  Buyer  buyer;                  Customer  customer1  =  createCustomer("HOGE|FUGA");                  Customer  customer2  =  createCustomer("HOGE|FUGA|HOGEHOGE");                  …                    buyer.add(customer1);                  buyer.add(customer2);                  …                  EXPECT_EQ(0,  buyer.getSecDon());  }  Customer  createCustomer(string  status)  {                  Customer  customer("Taro",  "Yamada",  15,  2,  status);                  customer.addCategory(STATE_ACTIVE);                  return  customer;  }   Parameterized  CreaDon  Method
  24. 24. TEST_P(HogeTest,  InvalidValueMinus)    {                  Hoge  hoge(-­‐1);                  EXPECT_EQ(0,  hoge.size());  }    TEST_P(HogeTest,  InvalidValueZero)    {                  Hoge  hoge(0);                  EXPECT_EQ(0,  hoge.size());  }    TEST_P(HogeTest,  InvalidValueTooBig)    {                  Hoge  hoge(124566);                  EXPECT_EQ(0,  hoge.size());  }  …  
  25. 25. 重複するコードTEST_P(HogeTest,  InvalidValueMinus)    {                  Hoge  hoge(-­‐1);                  EXPECT_EQ(0,  hoge.size());  }    TEST_P(HogeTest,  InvalidValueZero)    {                  Hoge  hoge(0);                  EXPECT_EQ(0,  hoge.size());  }    TEST_P(HogeTest,  InvalidValueTooBig)    {                  Hoge  hoge(124566);                  EXPECT_EQ(0,  hoge.size());  }  …  
  26. 26. 共通化するclass  HogeTest  :  public  tesDng::TestWithParam<int>  {};   INSTANTIATE_TEST_CASE_P(InvalidValueInstance,  HogeTest,                    tesDng::Values(-­‐1,  0,  10000));   TEST_P(HogeTest,  hogehoge)    {    Hoge  hoge(GetParam());    EXPECT_EQ(0,  hoge.size());  }   Parameterized  Test  
  27. 27. Fragile  Tests問題から 逃れるためには
  28. 28. テストファースト   リファクタリング   RED による追加・変更 (RED→GREEN) (Refactor) Green REFACT GREEN OR
  29. 29. TDDの三原則
  30. 30. TDDの三原則 テストファースト   リファクタリング   RED による追加・変更 (RED→GREEN) (Refactor) Green REFACT GREEN OR 愚直に続ければ Fragile  Testsの状態に堕ちる
  31. 31. TDDの基本原則はテストの保守性を⼗十分に保障しない なにもしなければ     F  r  a  g  i  l  e    T  e  s  t  s エントロピーが増⼤大していく
  32. 32. ただよく⾒見見ると TDDの達⼈人や きちんとしたTDD本では 合間を縫ってテストコードを改善している
  33. 33. Fragile  Tests問題から 逃れるためには
  34. 34. テストファースト   テストコードの   による追加・変更 設計改善   RED (RED→GREEN) (REFACTOR[TEST]) REFACTOR •  TEST GREEN Green •  PRODUCT テスト設計 を整える リファクタリング   テスト設計を   (Refactor[PRODUCT]) 整える
  35. 35. 継続的にテストの保守性を⾼高めよう製品コード・テストコードの 区別なくリファクタリング していこう
  36. 36. おわり

×