SlideShare a Scribd company logo
1 of 135
Download to read offline
ユニットテストの
保守性を作りこむ
  ~設計・実装の工夫で支える
 ユニットテストの継続的活用~
     rev.1.1   2011/1/29 @XP祭り関西2011

                     井芹       洋輝
謝辞
• 登壇者として声をかけていただいた細谷さん、
• 機会を提供して頂いたXPJUG関西の皆様
• 素晴らしい場を作り上げている登壇者・参加
  者・運営者の方々


 深くお礼申し上げます。
自己紹介
• 井芹洋輝(いせりひろき)
• 扱っているもの
 – 組込み開発/ソフトウェアテスト/開発者テスト
• 所属
 – WACATE実行委員/TDD研究会/ATECなど
• 対外活動
 – JaSST’11 Tokyo/WACATE2011冬/Androidテスト祭り等
 – ソフトウェアテストPRESS総集編/Ultimate agile Stories
概要
• ユニットテストの保守性を作りこむアプ
  ローチを、いくつかの具体例を交えて俯
  瞰的に見ていきます
概要
1. 背景
 – ユニットテストの現状と課題
2. 目標
 – ユニットテスト継続活用における目標
3. ユニットテストの保守性向上アプローチ
 –   テストコードの実装の工夫
 –   テストコードの構造設計の工夫
 –   テスト設計の工夫
4. まとめ
背景
ユニットテストの用途
  【現在編】
軽快なチェック
//コードから無視する文字を削除する
string reformat(string line)
{
        ...(複雑なロジック)...
}
                               複雑なメソッドを書いた
                               きちんと動くか不安だ
//コードから無視する文字を削除する
string reformat(string line)
{
        ...(複雑なロジック)...
}

                            安心できるまでテストを書く
TEST(CodeAnalyzer, reformatContainComment)
{
   EXPECT_EQ("#hoge", reformat("#hoge /* fuga */"));
}
TEST(CodeAnalyzer, reformatContainSpace)
{
   EXPECT_EQ("void function()", reformat("void function ()"));
}
TEST(CodeAnalyzer, reformatContainEmptyLine)
{
   EXPECT_EQ("test;¥n", reformat("test;¥n¥n¥n¥n"));
}
…
//コードから無視する文字を削除する
string reformat(string line)
{
        ...(複雑なロジック)...
}

                          安心できるまでテストを書く
TEST(CodeAnalyzer, reformatContainComment)
{
   EXPECT_EQ("#hoge", reformat("#hoge /* fuga */"));
}
TEST(CodeAnalyzer, reformatContainSpace)
{
   EXPECT_EQ("void function()", reformat("void function ()"));
}
TEST(CodeAnalyzer, reformatContainEmptyLine)
{
   EXPECT_EQ("test;¥n", reformat("test;¥n¥n¥n¥n"));
}
…    リスクや不安を即時に解消して前進できる
リファクタリング
//うるう年か判定する
bool isLeapYear(unsigned int year)
{
     if (year % 4 == 0)
     {
           if (year % 100 == 0)
           {                            実装が汚い
                 if (year % 400 == 0)
                 {
                       return true;
                 }
                 return false;
           }
           return true;
     }
     return false;
}
1. テストで保護する
                                        TEST(TestYear, isLeapYearDivisibleBy4)
//うるう年か判定する                             {
bool isLeapYear(unsigned int year)
                                           EXPECT_EQ(true, isLeapYear(8));
{
                                           EXPECT_EQ(false, isLeapYear(9));
     if (year % 4 == 0)
                                           EXPECT_EQ(true, isLeapYear(0));
     {
                                        }
           if (year % 100 == 0)
           {
                                        TEST(TestYear, isLeapYearDivisibleBy400)
                 if (year % 400 == 0)
                                        {
                 {
                                           EXPECT_EQ(true, isLeapYear(800));
                       return true;
                                           EXPECT_EQ(false, isLeapYear(900));
                 }
                                        }
                 return false;
           }
                                        TEST(TestYear, isLeapYearDivisibleBy100)
           return true;
                                        {
     }
                                           EXPECT_EQ(false, isLeapYear(500));
     return false;
                                        }
}
1. テストで保護する
                                                 TEST(TestYear, isLeapYearDivisibleBy4)
                                                 {
                                                    EXPECT_EQ(true, isLeapYear(8));
//うるう年か判定する                                         EXPECT_EQ(false, isLeapYear(9));
bool isLeapYear(unsigned int year)                  EXPECT_EQ(true, isLeapYear(0));
{                                                }
     if (year % 400 == 0)
     {                                           TEST(TestYear, isLeapYearDivisibleBy400)
            return true;                         {
     }                                              EXPECT_EQ(true, isLeapYear(800));
     if ((year % 4 == 0) && (year % 100 != 0))      EXPECT_EQ(false, isLeapYear(900));
     {                                           }
            return true;
     }                                           TEST(TestYear, isLeapYearDivisibleBy100)
     return false;                               {
}                                                   EXPECT_EQ(false, isLeapYear(500));

2. テストでチェックしつつ                                   }


リファクタリング
1. テストで保護する
                                                 TEST(TestYear, isLeapYearDivisibleBy4)
                                                 {
                                                    EXPECT_EQ(true, isLeapYear(8));
//うるう年か判定する                                         EXPECT_EQ(false, isLeapYear(9));
bool isLeapYear(unsigned int year)                  EXPECT_EQ(true, isLeapYear(0));
{                                                }
     if (year % 400 == 0)
     {                                           TEST(TestYear, isLeapYearDivisibleBy400)
            return true;                         {
     }                                              EXPECT_EQ(true, isLeapYear(800));
     if ((year % 4 == 0) && (year % 100 != 0))      EXPECT_EQ(false, isLeapYear(900));
     {                                           }
            return true;
     }                                           TEST(TestYear, isLeapYearDivisibleBy100)
     return false;                               {
}                                                   EXPECT_EQ(false, isLeapYear(500));

2. テストでチェックしつつ                                   }


リファクタリング
                                                                安全に記述改善
学習テスト
boost::xpressive

                    初使用で
                   よくわからない
boost::xpressive
テストで動作を確認する。不安がなくなるまで試す
TEST(regex, regexFileseek)
{
   namespace xp = boost::xpressive;
   string target; xp::smatch match;
   xp::sregex rex = xp::sregex::compile ("(¥¥.c|¥¥.h)$");

     target = "test";
     EXPECT_EQ(false, xp::regex_search(target, match, rex));

     target = "test.c";
     EXPECT_EQ(true, xp::regex_search(target, match, rex));

     target = "test.h";
     EXPECT_EQ(true, xp::regex_search(target, match, rex));

     target = "./../source/_svn/text-base/main.c.svn-base";
     EXPECT_EQ(false, xp::regex_search(target, match, rex));

     target = "test.cpp";
     EXPECT_EQ(false, xp::regex_search(target, match, rex));
}
boost::xpressive
テストで動作を確認する。不安がなくなるまで試す
TEST(regex, regexFileseek)
{
   namespace xp = boost::xpressive;
   string target; xp::smatch match;
   xp::sregex rex = xp::sregex::compile ("(¥¥.c|¥¥.h)$");

     target = "test";
     EXPECT_EQ(false, xp::regex_search(target, match, rex));

     target = "test.c";
     EXPECT_EQ(true, xp::regex_search(target, match, rex));

     target = "test.h";
     EXPECT_EQ(true, xp::regex_search(target, match, rex));

     target = "./../source/_svn/text-base/main.c.svn-base";
     EXPECT_EQ(false, xp::regex_search(target, match, rex));

    動作の勉強とチェック
     target = "test.cpp";
     EXPECT_EQ(false, xp::regex_search(target, match, rex));
}
    コードのドキュメントとして活用
デバッギングテスト
class MacroWord




                  バグがでた
class MacroWord

1. テスト上でバグを再現する
TEST_F(TestMacroWord, macroDataMacroWordBug21)
{
   MacroData macroData;
   macroData.push_back("AUTO_DEBUG_1");
   macroData.push_back("AUTO_DEBUG_2");
   macroData.push_back("AUTO_DEBUG_2");
   macroData.push_back("AUTO_DEBUG_2");
   macroData.push_back(“BB_H_");

    MacroWord macroWord(macroData);

    EXPECT_EQ("AUTO_DEBUG_1", macroWord.data_[0].macroName_);
    EXPECT_EQ(1, analyzer.data_[0].number);

    EXPECT_EQ("AUTO_DEBUG_2", macroWord.data_[1].macroName_)
    EXPECT_EQ(3, analyzer.data_[1].number);

    EXPECT_EQ(“BB_H_", macroWord.data_[2].macroName_);
    EXPECT_EQ(1, analyzer.data_[2].number);
}
class MacroWord

1. テスト上でバグを再現する
2. テストでバグを絞込み特定する
TEST_F(TestMacroWord, MacroWordBug21)
{
   MacroData macroData;

    macroData.push_back("AUTO_DEBUG_2");
    macroData.push_back("AUTO_DEBUG_2");
    macroData.push_back("AUTO_DEBUG_2");

    MacroWordProxy::wordCount(macroData);

    EXPECT_EQ(3, MacroWordProxy::getSize(0));
}
class MacroWord

1. テスト上でバグを再現する
2. テストでバグを絞込み特定する
TEST_F(TestMacroWord, MacroWordBug21)
{
   MacroData macroData;

    macroData.push_back("AUTO_DEBUG_2");
    macroData.push_back("AUTO_DEBUG_2");
    macroData.push_back("AUTO_DEBUG_2");

    MacroWordProxy::wordCount(macroData);

    EXPECT_EQ(3, MacroWordProxy::getSize(0));
}

3. 修正後テストがパスすることを確認する
class MacroWord

1. テスト上でバグを再現する
2. テストでバグを絞込み特定する
TEST_F(TestMacroWord, macroWordBug21)
{
   MacroData macroData;

    macroData.push_back("AUTO_DEBUG_2");
    macroData.push_back("AUTO_DEBUG_2");
    macroData.push_back("AUTO_DEBUG_2");

    MacroWordProxy::wordCount(macroData);

    EXPECT_EQ(3, MacroWordProxy::getSize(0));
}

3. 修正後テストがパスすることを確認する
バグを再現               バグを特定               バグ修正のチェック
その他ユニットテストの活用
  テスト駆動開発              CIによる自動回帰テスト




         RED



REFACT
               GREEN
  OR
ユニットテストの効能
•   バグを検出する
•   バグ発生箇所を絞り込む
•   バグ混入を監視する
•   機能的な保証を行う
•   設計支援を行う
•   ドキュメントとなる
ツール・方法論が発達した今では
プログラミングとユニットテスト
が一体となり、プログラマはプロ
グラミングの最初から最後まで継
続的にユニットテストのサポート
を受けられるようになっている
ユニットテストの継続活用
   における課題
ユニットテストの継続活用におい
ては保守性がクリティカルな問題
となりえる
保守性に問題を持つユニットテス
トは、再利用の度に冗長なコスト
を累積させる
可読性の悪いテスト
TEST(TestHoge, Hoge)
{
   stringstream ss;
   int i, j;
   Inspector inspector("hoge", "fuga");
   EXPECT_EQ(false, inspector.isEmpty());
   inspector.pushLine("this is test.");
   inspector.pushLine("this is test.");
   EXPECT_EQ(6, inspector.getWords());
   for (j = 0; j < 100; j++) {
           for (i = 0; i < j; i++) {
                  ss << j;
                  ss << " ";
                  ss << i;
                  inspector.pushLine(ss.str());
              EXPECT_EQ(INFO, inspector.getState());
          }
          inspector.addSection();
         EXPECT_EQ(j, inspector.getSection());
     }
     EXPECT_EQ(0, inspector.runInspection());
}
TEST(TestHoge, Hoge)
{
   stringstream ss;
   int i, j;
   Inspector inspector("hoge", "fuga");
   EXPECT_EQ(false, inspector.isEmpty());
   inspector.pushLine("this is test.");                 何を検証している
   inspector.pushLine("this is test.");                 のか分からない
   EXPECT_EQ(6, inspector.getWords());
   for (j = 0; j < 100; j++) {
           for (i = 0; i < j; i++) {
                  ss << j;                              バグはどこにある
                  ss << " ";                            のか分からない
                  ss << i;
                  inspector.pushLine(ss.str());
              EXPECT_EQ(INFO, inspector.getState());
                                                        正しいのかどうか
          }
                                                         わからない
          inspector.addSection();
         EXPECT_EQ(j, inspector.getSection());
     }
     EXPECT_EQ(0, inspector.runInspection());
}                                                      Assertion Roulette
TEST(TestHoge, Hoge)
{
   stringstream ss;
   int i, j;
   Inspector inspector("hoge", "fuga");
   EXPECT_EQ(false, inspector.isEmpty());
   inspector.pushLine("this is test.");                 何を検証している
   inspector.pushLine("this is test.");                 のか分からない
   EXPECT_EQ(6, inspector.getWords());
   for (j = 0; j < 100; j++) {
           for (i = 0; i < j; i++) {
                  ss << j;                              バグはどこにある
                  ss << " ";                            のか分からない
                  ss << i;
                  inspector.pushLine(ss.str());
              EXPECT_EQ(INFO, inspector.getState());
                                                        正しいのかどうか
          }
                                                         わからない
          inspector.addSection();
         EXPECT_EQ(j, inspector.getSection());
     }
     EXPECT_EQ(0, inspector.runInspection());
}                                                      Assertion Roulette
テストの再利用コストを増大させる
変更性の悪いテスト
(テストコードの重複/
  Fragile Test)
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);
    …
}
TEST(testHoge, InspectionFugaHoge)
{
   MotorStatus motorStatus(133, 232);
   MaintenanceData mtData;
   MaintenanceType mtType(createRegionID(JAPAN));
   setInitialData(mtData, mtType);

    InspectionFuga inspector;
    inspector.set(createMaintenanceInfo(mtData, mtType), motorStatus);
    …
}

                                             似たような記述が多数存在・・
TEST(testHoge, InspectionFugaHoge)
{
   MotorStatus motorStatus(133, 232);
   MaintenanceData mtData;
   MaintenanceType mtType(createRegionID(JAPAN));
   setInitialData(mtData, mtType);

     InspectionFuga inspector;
     inspector.set(createMaintenanceInfo(mtData, mtType), motorStatus);
     …
}
                                                              Fragile Test



                                     テストが製品コードの変更
    テストコードの変更箇所
       も特定困難
                                     コストを増大させる

                                     テストがテストコードの変更
    製品コードの変更コスト
       が大きい                          コストを増大させる
補足(Fragile Test)
• 製品コードとテストコードの過度な依存
  関係によって、製品コード/テストコード
  の変更コストが増大してしまう問題を
  Fragile Testsという
• Fragile Tests問題は継続的なユニットテ
  ストやTDDが抱える大きな問題であり、常
  に対策し続けなくてはならない
テストコードもレガシーコード化
する
ユニットテストを継続活用する環
境では、レガシーコード化したユ
ニットテストは最悪テストの効果
をマイナスに反転させる
ユニットテストのコストモデル
    (継続的にテストを作る場合)
               ユニットテスト
               の利益
ユニットテスト
規模




                         時間
               ユニットテスト
               保守コスト


          時間




                         時間
ユニットテストのコストモデル
    (継続的にテストを作る場合)
               ユニットテスト
               の利益
ユニットテスト
規模                       レガシーコード化




                         時間
               ユニットテスト
               保守コスト

                         レガシーコード化

          時間




                         時間
ユニットテストのコストモデル
    (継続的にテストを作る場合)
               ユニットテスト
               の利益

ユニットテスト
規模                       レガシーコード化




                         時間
               ユニットテスト
               保守コスト

                         レガシーコード化

          時間


 使えないテストの放棄とい
 う手段に・・・                 時間
ユニットテストはプログラミング
を強力に支援し得るが、一方でプ
ログラミングを強力に阻害し得る
ユニットテストはソフトウェアの
保守性を支えるが、一方でソフト
ウェアの保守性を阻害し得る
ユニットテストの継続活用
   のための目標
目標
               ユニットテスト
               の利益
ユニットテスト
規模




                         時間
               ユニットテスト
               運用コスト



          時間
                              保守性改善



                         時間
目標
               ユニットテスト
               の利益
ユニットテスト
規模




                         時間
               ユニットテスト
               運用コスト



          時間
                              保守性改善

 保守性改善により
 保守コストの増大を抑える            時間
テストとプロダクトの扱いに違い
はない。テストもプロセスを持ち
構造的設計、機能的設計を行う必
要がある。テストはプロダクトと
同じように保守性を作りこむ余地
がある。
テスト構造設計    テスト設計
テストコードの実装



テストコードの     テストの
 構造設計       上位設計




テストコードの     テスト設計
  実装        テスト実装
ユニットテストの
       保守性を支える原則
•   変更に対する堅牢性に優れる
•   可読性に優れる
•   独立性に優れる
•   自己完結している
•   完全自動化している
•   細粒度なテストケース
ユニットテストの
       保守性を支える原則
•   変更に対する堅牢性に優れる
•   可読性に優れる    テスト対象・テスト設計が変更
               されても、テストコードの変更
•   独立性に優れる
               が小さく済む
•   自己完結している
•   完全自動化している
•   細粒度なテストケース
ユニットテストの
       保守性を支える原則
•   変更に対する堅牢性に優れる
•   可読性に優れる    テストコードからテストの設計
               や意図を容易に読み取れる
•   独立性に優れる
•   自己完結している
•   完全自動化している
•   細粒度なテストケース
ユニットテストの
       保守性を支える原則
•   変更に対する堅牢性に優れる
•   可読性に優れる    構造軸:他のテストメソッド、テ
•   独立性に優れる    ストクラスの影響を受けない
               時間軸:テストの実行順序の影
•   自己完結している   響を受けない
•   完全自動化している
•   細粒度なテストケース
ユニットテストの
        保守性を支える原則
•   変更に対する堅牢性に優れる
•   可読性に優れる
              Setup、テスト実行、結果の検証、
•   独立性に優れる   Teardownの一連の処理が細か
•   自己完結している 粒度で完結している
•   完全自動化している
•   細粒度なテストケース
ユニットテストの
       保守性を支える原則
•   変更に対する堅牢性に優れる
•   可読性に優れる
•   独立性に優れる
•   自己完結している  テストを実行する処理を完全に
•   完全自動化している 自動化できる
•   細粒度なテストケース
ユニットテストの
       保守性を支える原則
•   変更に対する堅牢性に優れる
•   可読性に優れる
•   独立性に優れる
•   自己完結している
•   完全自動化している
•   細粒度なテストケース テストメソッドが十分に細分化さ
                 れている
ユニットテストの
 保守性作りこみアプローチ
1. 実装の工夫
2. 構造設計の工夫
3. 設計の工夫
ユニットテストの保守性作りこみ
    アプローチ1
   実装の工夫
ユニットテストの実装はプログラ
ミング行為そのものである
保守性を高めるパターンを適用し
継続的に記述改善する必要がある
コードの共通化
• 重複する記述は共通化する
• 便利なロジックは汎用化する
TEST(Buyer, 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.getSection());
}
TEST(Buyer, 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.getSection());
}

Parameterized Creation Method
Customer createCustomer(string status)
{
    Customer customer("Taro", "Yamada", 15, 2, status);
    customer.addCategory(STATE_ACTIVE);
    return customer;
}
TEST(Buyer, addSameStatus)
{
   Buyer buyer;
   Customer customer1 = createCustomer("HOGE|FUGA");
   Customer customer2 = createCustomer("HOGE|FUGA|HOGEHOGE");

    buyer.add(customer1);
                 重複部分をCreation
    buyer.add(customer2);                        Methodで共通化
    EXPECT_EQ(0, buyer.getSection());
}



Parameterized Creation Method
Customer createCustomer(string status)
{
    Customer customer("Taro", "Yamada", 15, 2, status);
    customer.addCategory(STATE_ACTIVE);
    return customer;
}
TEST(TestItemList, ItemPush)
{
   …
   EXPECT_EQ(expectItem.getName(), item.getName());
   EXPECT_EQ(expectItem.getID(), item.getID());
   EXPECT_EQ(expectItem.getSize(), item.getSize());
}
TEST(TestItemList, itemPush)
{                                  似た記述が大量に散在
   …
   EXPECT_EQ(expectItem2.getName(), item2.getName());
   EXPECT_EQ(expectItem2.getID(), item2.getID());
   EXPECT_EQ(expectItem2.getSize(), item2.getSize());
}
TEST(TestItemList, itemPush)
{
   …
   EXPECT_EQ(expectItem.getName(), item.getName());
   EXPECT_EQ(expectItem.getID(), item.getID());
   EXPECT_EQ(expectItem.getSize(), item.getSize());
}
TEST(TestItemList, itemPush)
{                                  似た記述が大量に散在
   …
   EXPECT_EQ(expectItem2.getName(), item2.getName());
   EXPECT_EQ(expectItem2.getID(), item2.getID());
   EXPECT_EQ(expectItem2.getSize(), item2.getSize());
}


Custom Assertion
#define EXPECT_ITEM_EQ(expect, actual) ¥
EXPECT_EQ((expect).getName(), (actual).getName()); ¥
EXPECT_EQ((expect).getID(), (actual).getID()+1); ¥
EXPECT_EQ((expect).getSize(), (actual).getSize());
TEST(TestItemList, itemPush)
{
   …
   EXPECT_ITEM_EQ(expectItem, item);


}
      重複部分を拡張Assertionで共通化
TEST(TestItemList, test_itemPush)
{
   …
   EXPECT_ITEM_EQ(expectItem2, item2);


}


Custom Assertion
#define EXPECT_ITEM_EQ(expect, actual) ¥
EXPECT_EQ((expect).getName(), (actual).getName()); ¥
EXPECT_EQ((expect).getID(), (actual).getID()+1); ¥
EXPECT_EQ((expect).getSize(), (actual).getSize());
可読性の向上
• 重要なものを目立たせる
• 適切な名前に置き換える
• 小さくする
Customer customer2("Taro", "Yamada", 15, 2, "HOGE|FUGA|HOGEHOGE");
                      何でもいいダミー値                     テストしたい値
Customer customer2("Taro", "Yamada", 15, 2, "HOGE|FUGA|HOGEHOGE");
                      何でもいいダミー値                     テストしたい値


Parameterized Creation Method
Customer customer2 = createCustomer("HOGE|FUGA|HOGEHOGE");

                   ダミー値を隠し、重要なパラメータを強調する

                   重要なものを目立たせる

                   ※隠ぺいはトレードオフなので要注意
TEST(testHoge, Fuga)
{
     MotorStatus motorStatus(133, 232);
     InspectionFuga inspector;
     inspector.set(createMaintenanceInfo(motorStatus);

      EXPECT_EQ(START, inspector.getState());
      EXPECT_EQ(true, inspector.isEmpty());

      inspector.initialize();

      EXPECT_EQ(INFO, inspector.getState());
      EXPECT_EQ(false, inspector.isEmpty());
}
TEST(testHoge, Fuga)
{
     MotorStatus motorStatus(133, 232);
     InspectionFuga inspector;
     inspector.set(createMaintenanceInfo(motorStatus);

      EXPECT_EQ(START, inspector.getState());
      EXPECT_EQ(true, inspector.isEmpty());

      inspector.initialize();

      EXPECT_EQ(INFO, inspector.getState());
      EXPECT_EQ(false, inspector.isEmpty());
}

        1つのテストメソッドで色々検証しているため少し読みにくい
        分割で改善する
TEST(testHoge, Fuga)
{
       InspectionFuga inspector = createInspectionFugaDummy();

       EXPECT_EQ(START, inspector.getState());
       EXPECT_EQ(true, inspector.isEmpty());

       inspector.initialize();

       EXPECT_EQ(INFO, inspector.getState());
       EXPECT_EQ(false, inspector.isEmpty());
}

     分割時に重複するメソッドをあらかじめ抜き出す
TEST(testHoge, fugaConstractor)
{
       InspectionFuga inspector = createInspectionFugaDummy();

       EXPECT_EQ(START, inspector.getState());
       EXPECT_EQ(true, inspector.isEmpty());
}

TEST(testHoge, fugaInitialize)
{
       InspectionFuga inspector = createInspectionFugaDummy();
       inspector.initialize();

       EXPECT_EQ(INFO, inspector.getState());
       EXPECT_EQ(false, inspector.isEmpty());
}

                                  テストメソッドを小さくする
                 意図を読み取りやすい名前をつける
その他工夫
• テストメソッドをコンパクトに記述する
• テストコードの影響範囲を限定する
 – 時間軸、構造軸
• 危ういコードを分離する
 – 変更頻度の高いインターフェースをラッピン
   グする
 – テスト用インタフェースを用意する
その他工夫
• テストコードの保守性は製品コード・テ
  ストコード両方から支えられる
• 堅牢なユニットテストには堅牢な製品コ
  ードのインターフェースが不可欠である

       テスト        製品
       コード        コード


    テストが内部メンバを細かく参照する形は
    Fragile Testsになりえる
その他工夫
• テストコードの保守性は製品コード・テ
  ストコード両方から支えられる
• 堅牢なユニットテストには堅牢な製品コ
  ードのインターフェースが不可欠である
              堅牢な
              インターフェース


        テスト         製品
        コード         コード


    堅牢なインターフェースを製品コードが提供することで
    テストコードの堅牢性を高められる
ユニットテストの実装はプログラ
ミング行為そのものである
製品コード・テストコード両方に
対して、保守性を高めるパターン
を適用し継続的に記述改善する必
要がある
ユニットテストの保守性作りこみ
     アプローチ2
 構造設計の工夫
ユニットテストのコードは
Assertionの羅列ではない
テストコードも構造を持ち、それ
がユニットテストの保守性に影響
を与えるため、構造設計の視点が
必要になる
内部設計
テストのツリー構造

                                 Assertion
                     Test Case
                                 Assertion
        Test Suite
                     Test Case
ユニットテ
 スト
        Test Suite      …

            …
テストのツリー構造
                  細粒度・可読性
                                  Assertion
                      Test Case
                                  Assertion
         Test Suite

ユニットテ   少数のAssertionでTestCaseを構成する
                    Test Case
 スト                     (1条件/1テストケースなど
         Test Suite テスト設計の最小構成単位を反映)
                          …

             …   テスト設計やテストの意図が
                 分かりやすくなる
テストのツリー構造
   独立性、自己完結性の確保
                                 Assertion
                     Test Case
                                 Assertion
        Test Suite    独立・無干渉
                     Test Case
ユニットテ    独立・無干渉
 スト
        Test Suite      …

        変更や流用の影響を局所化できる
          …
テストのツリー構造
                              可読性など
Test Suite:テスト対象Class = n : 1               Assertion
  ※Fixture/外部コンポーネント等で分離        Test Case
                   通常は1:1
                                            Assertion
                  Test Suit
                                Test Case
   ユニットテ
    スト
                  Test Suit        …

 構造に対する網羅を…
 チェックしやすくする
ユニットテストの内部構造は一般
的にツリー構造をとる
そのため葉のコンパクト化、枝の
独立性向上、適切な分割といった
構造化設計の工夫が重要となる
それによりモジュール性や可読性
が向上し、ユニットテストの保守
性が作りこまれる
外部インターフェース設計
外部インターフェース
• 外部コンポーネントは保守性を低下させ
  るリスクになる

       テスト              テスト




              テスト対象


                              外部IF

             ブラックボックス
外部インターフェース
• 外部コンポーネントは保守性を低下させ
      ブラックボックスを介してテストが結合
  るリスクになる

       テスト              テスト




              テスト対象


                                外部IF

             ブラックボックス         状態を持つ
ユニットテストの保守性を損なう
外部コンポーネントは、外部イン
ターフェースの改善で分離する必
要がある

 外部コンポー               ブラックボック   ブラックボック
          StubやMock
 ネントを使用               スを使用する       ス
              など
 しないテスト                 テスト




              テスト対象
構造設計による改善
ユニットテストの内部構造や外部
インターフェースはその保守性に
影響するため、構造設計・アーキ
テクチャ設計を俯瞰的に洗練する
視点が要求される

ただし留意点が2つある
1:柔軟なズームアウト/
    ズームインが必要
• ユニットテストを継続活用する場合、ユ
  ニットテストはしばしばボトムアップに
  実装されるため、構造設計は実装状況に
  応じて柔軟に行わなければならない

        構造設計

               ズームアウト
               ズームイン

         実装
2:改善対象として製品コード/
 テストコードを区別しない
• ユニットテストの障害は、製品コード/テ
  ストコード両方から除去する
• 両者のインターフェースを統合的に洗練
  させる
class CameraCtrl

void CameraCtrl::hoge()
{
     _motorCtrl.run();      テスト対象が
     …                    外部コンポーネントに
}                           依存している

void CameraCtrl::fuga()    構造設計
{
     _motorCtrl.stop();
     …    外部コンポーネントを制御
}
                             実装
Test Suite
                    テストが
                 外部コンポーネントを
                   共有している


  CameraCtrl       構造設計

               ズームアウト


                    実装
   MotorCtrl
(外部コンポーネント)
外部コンポーネ
                                 ント
Test         Test
Suite        Suite            MockやStub等



                     テスタビリティの作りこみ



    CameraCtrl                        外部コンポーネントを
                                       置換可能にする


                                           構造設計




                                            実装
Test                   Test                       MotorCtrl
   Suite                  Suite

                                  Dependency Injection

                                         void CameraCtrl::CameraCtrl()
             CameraCtrl                  {
                                              _motorCtrl.open(...):
                                              ...
                                         }

    構造設計
                           void CameraCtrl::CameraCtrl(MemoryCtrl memoryCtrl)
ズームイン                      {
                                _motorCtrl = motorCtrl;
                                _motorCtrl.open(...):
        実装                      ...
                           }
Mock、       外部コンポー
右以外のテス
   ト
                     ネントを用い           MotorCtrl
         Stub等        るテスト




                              Dependency Injection


            CameraCtrl




   実装




  構造設計
ユニットテストのテストコードは
Assertionのリストではない
テストコードも構造を持ち、それ
がユニットテストの保守性に影響
を与える
継続的な構造設計の改善で、テス
トの保守性を高めよう
実装・構造設計の参考図書
• xUnit Test Patterns
  – –Refactoring Test Code


• 読書会サイトに翻訳情報
  あり
  – <http://www.fieldnotes.jp/xutp/>
  – 「xutp読書会」で検索
ユニットテストの保守性作りこみ
     アプローチ3

  設計の工夫
設計の工夫
1. テスト設計を洗練する
2. トップダウンのテスト設計で保守性を作
   りこむ
テスト設計の洗練
ユニットテストの継続的活用
    においての留意点
 • 作りすぎたテストを継続的に保守しようとす
   ると保守性に悪影響を与える
                            テストコード
                    TEST(…)
                    {
         製品コード         …
                       EXPECT_EQ(…, Hoge());
    void Hoge()     }
    {               TEST(…)
         …          {
    }                  …
                       EXPECT_EQ(…, Hoge());
                    }
製品コードを変更する        TEST(…)
                  {
と大量のテストがビルドエラー        …
                      EXPECT_EQ(…, Hoge());
                  }
                               テスト設計を変更する
                               と修正が複数にまたがる
保守性を高めるにはコンパクトな
テストで十分な網羅性を確保する
必要がある
その実現にテスト設計技法やテス
ティングリテラシーの素養は有効
である
境界値分析
• 入出力値をグルーピング(例えば同値分
  割)して、グループの境界の値を抽出す
  る
• 欠陥が境界付近に偏在するという経験則
  に立脚
境界値分析
• 「6歳未満は無料。6歳以上12歳以下は半
  額。13以上は定額」
境界値分析
• 「6歳未満は無料。6歳以上12歳以下は半
  額。13以上は定額」
-∞                                        +∞

             -1
     ありえない
             0         5
                  無料
                       6        12
                           半額
                                13
                                     定額
カバレッジ分析
• 制御フローの網羅度を基準にテスト設計
  を行う
カバレッジ分析
start
  入力:ループ回数




      任意の回数
      ループ




end
カバレッジ分析
start
  入力:ループ回数
              カバレッジレベル6(C6)
              テストで用いるループ回数:
               0回
      任意の回数    1回
      ループ
               頻出する代表値
               最大回


end
テストの目的に応じて柔軟に
   設計技法を使い分ける
 仕様




テスト設計   その他




コード構造
テストの目的に応じて柔軟に
   設計技法を使い分ける
               4で割り切れる                         N       Y       Y   Y
                                                                       機能的な保証
 仕様            100で割り切れる                       N       N       Y   Y   テストファースト
               400で割り切れる                       N       N       N   Y
                                                                       etc..

               うるうどし                           N       Y       N   Y



テスト設計   その他

              //うるう年か判定する
              bool isLeapYear(unsigned int year)
              {
                   if (year % 400 == 0)                                機械的なリファクタリング
                   {
                         return true;                                  テスタビリティの評価
                   }                                                   etc..
                   if ((year % 4 == 0) && (year % 100 != 0))
コード構造              {
                         return true;
                   }
                   return false;
              }
テストの目的に応じて柔軟に
設計技法や考え方を応用する
                 TEST(…)
任意の値でいいけど        {
取り合えず境界値を           …
  指定しよう             EXPECT_EQ(?, ?);
                 }



                 /**
仕様が厳密なので仕様ベー      * @brief …詳細な関数仕様…
スのテスト設計ですまそう      */
                 void fuga(…) {
                 }
                 bool hoge(unsigned int year)
仕様が不明だけど単純な分     {
                      if (year % 400 == 0)
岐構造なのでC3のテストを用        {
意してリファクタリングしよう              return true;
                      }
                      if ((year % 4 == 0) && (year % 100 != 0))
                      {
                            return true;
                      }
                      return false;
                 }
テスト設計の技法や考え方のレパ
ートリーが増えればより洗練され
たテストが書けるようになり、ユ
ニットテストの保守性向上につな
がる
テスト設計技法 参考図書
2.トップダウンのテスト設計で
    保守性を作りこむ
テスト設計フロー
  テストコード実装フロー   テスト設計フロー


    テストコードの
     構造設計        テスト設計




    テストコードの
                 テスト実装
      実装



ユニットテストの継続的活用におけるテスト設計フロー
テスト設計フロー


           テスト条件、テスト設計技法等を整理する
 テスト設計     テストケースを求める、等




 テスト実装     テストケースの選定を行う
           テストに用いる具体値を求める、等
俯瞰的なテスト設計もユニットテ
ストの保守性の作りこみにとって
必須である
テストコードの構造設計と同様、
柔軟なズームアウト/ズームインで
洗練されたテスト設計を実現しよ
う
テスト条件の抽出による
外部インターフェースの洗練
 テストコード実装フロー       テスト設計フロー


   テストコードの
    構造設計             テスト設計




   テストコードの
                     テスト実装
     実装



   ユニットテストの継続的活用におけるテスト設計フロー
2. トップダウンでインターフェース設計             1. テスト条件を抽出

                DB   UART          ●テスト条件リスト
  通常テスト
               テスト   テスト           ・DB
                                   ・タッチパネル
                            …
                                   ・メカニカルボタン
                                   ・UART通信
 DB   UART
           …   DB    UART          ….
スタブ   スタブ


           ユニットテストの制約となる
         テストコードの実装     テスト設計プロセス
           外部コンポーネントを抽出し、構造設計に反映させる
          テストコードの
                                テスト設計
           構造設計



          テストコードの
            実装                  テスト実装


        全体整合のとれた外部インターフェースを構築
テスト対象の安定度分析による
 ユニットテストの作りこみ
 テストコード実装フロー       テスト設計フロー



   テストコードの
                     テスト設計
    構造設計




   テストコードの
                     テスト実装
     実装



   ユニットテストの継続的活用におけるテスト設計フロー
2. 変更リスクの少ないテストを作りこみ                          1. テスト対象の安定度評価

テストの品質                    Hoge   Fuga   Piyo   …
                                                        ファイル       変更step/week
           ゴールとなる水準
                      1   ○      ○
                                                        Hoge.cpp   0

                      2          ○      ○               Fuga.cpp   23

                                                        PIyo.cpp   133
                      3
                                                        …          …
                      …
           開発時間

     安定したプログラムユニットを抽出し、イテレーティブな
       テストコードの実装    テスト設計プロセス
     ユニットテストの作りこみに反映する
         テストコードの
                                               テスト設計
          構造設計



         テストコードの
                                               テスト実装
           実装

         テストの作りすぎによるデメリットを軽減する
テスト計画/テストの上位設計
     の重要性
• 開発中継続的にユニットテストを構築し
  ていく場合
開発中継続的にユニットテストを
構築していく場合、テスト計画・
テスト上位設計は特に重要である
望ましいテストは何か、いつどの
ようなテストを確保すべきか、ど
のようにテストを管理するかトッ
プダウンで決めることで、柔軟か
つ洗練されたテストを確保できる
テスト計画・テスト上位設計
• テスト目的、テスト対象
• 望ましいテストの構造
 – テストクラスの粒度
     • Feature/Class/Fixture/Method/Story
 – 望ましいAssertionの数
 – テストスイートの粒度
• テストをどのように配置するか
 –   テストレベル/テストタイプ/テストフェーズ/テストの目的
• 期待するテストの網羅性
 – ソフトウェアのどこをテストするか
     • コンポーネント/パッケージ/外部コンポーネント
 – カバレッジはどの程度か
     • 構造的カバレッジ/機能的カバレッジ
テスト計画・テスト上位設計
• テストの品質の管理・保証方法
 – カバレッジやテストコード等の管理
   • どう維持するか/いつどのように保証するか
• テスト環境の整備
 – Test Doubleの開発管理
 – ツールや環境の管理
• フェーズや計画
 – どの段階でどの程度のテストを確保するか
テストコードと同じく、テスト設
計も上位構造を持つ
保守性の障害となるテスト条件や
制約、テスト設計の抽象構造を抽
出し、下位の設計に反映させてい
こう
まとめ
ユニットテストの実装はプログラ
ミング行為そのもの
保守性を高めるパターンを適用し
、継続的に記述改善しよう
テストコードはAssertの羅列では
ない
保守性に優れたアーキテクチャ・
構造をテストコードに持たせよう
また構造のズームアウト/ズームイ
ンを柔軟に行って、継続的にテス
トコードの設計を改善させていこ
う
テスト設計はテストコードの保守
性を左右する
保守性に優れたテストを書くため
テスト設計技法、リテラシーをど
んどん身につけよう
テスト設計でもトップダウンでテ
スト設計の改善をすすめよう
テスト計画・上位設計でより良い
テストを効率的に確保しよう
ご清聴ありがとうございました

More Related Content

What's hot

Dockerの期待と現実~Docker都市伝説はなぜ生まれるのか~
Dockerの期待と現実~Docker都市伝説はなぜ生まれるのか~Dockerの期待と現実~Docker都市伝説はなぜ生まれるのか~
Dockerの期待と現実~Docker都市伝説はなぜ生まれるのか~Masahito Zembutsu
 
Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Amazon Cognito使って認証したい?それならSpring Security使いましょう!Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Amazon Cognito使って認証したい?それならSpring Security使いましょう!Ryosuke Uchitate
 
[Aurora事例祭り]Amazon Aurora を使いこなすためのベストプラクティス
[Aurora事例祭り]Amazon Aurora を使いこなすためのベストプラクティス[Aurora事例祭り]Amazon Aurora を使いこなすためのベストプラクティス
[Aurora事例祭り]Amazon Aurora を使いこなすためのベストプラクティスAmazon Web Services Japan
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」Takuto Wada
 
クラウド環境下におけるAPIリトライ設計
クラウド環境下におけるAPIリトライ設計クラウド環境下におけるAPIリトライ設計
クラウド環境下におけるAPIリトライ設計Kouji YAMADA
 
インフラエンジニアの綺麗で優しい手順書の書き方
インフラエンジニアの綺麗で優しい手順書の書き方インフラエンジニアの綺麗で優しい手順書の書き方
インフラエンジニアの綺麗で優しい手順書の書き方Shohei Koyama
 
Java ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugJava ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugMasatoshi Tada
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪Takuto Wada
 
40歳過ぎてもエンジニアでいるためにやっていること
40歳過ぎてもエンジニアでいるためにやっていること40歳過ぎてもエンジニアでいるためにやっていること
40歳過ぎてもエンジニアでいるためにやっていることonozaty
 
こんなに使える!今どきのAPIドキュメンテーションツール
こんなに使える!今どきのAPIドキュメンテーションツールこんなに使える!今どきのAPIドキュメンテーションツール
こんなに使える!今どきのAPIドキュメンテーションツールdcubeio
 
マルチテナント化で知っておきたいデータベースのこと
マルチテナント化で知っておきたいデータベースのことマルチテナント化で知っておきたいデータベースのこと
マルチテナント化で知っておきたいデータベースのことAmazon Web Services Japan
 
Redisの特徴と活用方法について
Redisの特徴と活用方法についてRedisの特徴と活用方法について
Redisの特徴と活用方法についてYuji Otani
 
ドメイン駆動設計サンプルコードの徹底解説
ドメイン駆動設計サンプルコードの徹底解説ドメイン駆動設計サンプルコードの徹底解説
ドメイン駆動設計サンプルコードの徹底解説増田 亨
 
5分で解るセキュアコーディング
5分で解るセキュアコーディング5分で解るセキュアコーディング
5分で解るセキュアコーディングYasuo Ohgaki
 
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考えるGoのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考えるpospome
 

What's hot (20)

Dockerの期待と現実~Docker都市伝説はなぜ生まれるのか~
Dockerの期待と現実~Docker都市伝説はなぜ生まれるのか~Dockerの期待と現実~Docker都市伝説はなぜ生まれるのか~
Dockerの期待と現実~Docker都市伝説はなぜ生まれるのか~
 
Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Amazon Cognito使って認証したい?それならSpring Security使いましょう!Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Amazon Cognito使って認証したい?それならSpring Security使いましょう!
 
[Aurora事例祭り]Amazon Aurora を使いこなすためのベストプラクティス
[Aurora事例祭り]Amazon Aurora を使いこなすためのベストプラクティス[Aurora事例祭り]Amazon Aurora を使いこなすためのベストプラクティス
[Aurora事例祭り]Amazon Aurora を使いこなすためのベストプラクティス
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
 
クラウド環境下におけるAPIリトライ設計
クラウド環境下におけるAPIリトライ設計クラウド環境下におけるAPIリトライ設計
クラウド環境下におけるAPIリトライ設計
 
FIDO認証によるパスワードレスログイン実装入門
FIDO認証によるパスワードレスログイン実装入門FIDO認証によるパスワードレスログイン実装入門
FIDO認証によるパスワードレスログイン実装入門
 
インフラエンジニアの綺麗で優しい手順書の書き方
インフラエンジニアの綺麗で優しい手順書の書き方インフラエンジニアの綺麗で優しい手順書の書き方
インフラエンジニアの綺麗で優しい手順書の書き方
 
At least onceってぶっちゃけ問題の先送りだったよね #kafkajp
At least onceってぶっちゃけ問題の先送りだったよね #kafkajpAt least onceってぶっちゃけ問題の先送りだったよね #kafkajp
At least onceってぶっちゃけ問題の先送りだったよね #kafkajp
 
Java ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugJava ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsug
 
Docker Compose 徹底解説
Docker Compose 徹底解説Docker Compose 徹底解説
Docker Compose 徹底解説
 
ヤフー社内でやってるMySQLチューニングセミナー大公開
ヤフー社内でやってるMySQLチューニングセミナー大公開ヤフー社内でやってるMySQLチューニングセミナー大公開
ヤフー社内でやってるMySQLチューニングセミナー大公開
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪
 
40歳過ぎてもエンジニアでいるためにやっていること
40歳過ぎてもエンジニアでいるためにやっていること40歳過ぎてもエンジニアでいるためにやっていること
40歳過ぎてもエンジニアでいるためにやっていること
 
こんなに使える!今どきのAPIドキュメンテーションツール
こんなに使える!今どきのAPIドキュメンテーションツールこんなに使える!今どきのAPIドキュメンテーションツール
こんなに使える!今どきのAPIドキュメンテーションツール
 
Spring Boot on Kubernetes : Yahoo!ズバトク事例 #jjug_ccc
Spring Boot on Kubernetes : Yahoo!ズバトク事例 #jjug_cccSpring Boot on Kubernetes : Yahoo!ズバトク事例 #jjug_ccc
Spring Boot on Kubernetes : Yahoo!ズバトク事例 #jjug_ccc
 
マルチテナント化で知っておきたいデータベースのこと
マルチテナント化で知っておきたいデータベースのことマルチテナント化で知っておきたいデータベースのこと
マルチテナント化で知っておきたいデータベースのこと
 
Redisの特徴と活用方法について
Redisの特徴と活用方法についてRedisの特徴と活用方法について
Redisの特徴と活用方法について
 
ドメイン駆動設計サンプルコードの徹底解説
ドメイン駆動設計サンプルコードの徹底解説ドメイン駆動設計サンプルコードの徹底解説
ドメイン駆動設計サンプルコードの徹底解説
 
5分で解るセキュアコーディング
5分で解るセキュアコーディング5分で解るセキュアコーディング
5分で解るセキュアコーディング
 
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考えるGoのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
 

Viewers also liked

TDDを実践してわかったTDDつまづくあるあると自分なりの乗り越え方まとめ
TDDを実践してわかったTDDつまづくあるあると自分なりの乗り越え方まとめTDDを実践してわかったTDDつまづくあるあると自分なりの乗り越え方まとめ
TDDを実践してわかったTDDつまづくあるあると自分なりの乗り越え方まとめKei Sawada
 
アジャイル開発とTDDを半年間実践してみた顛末と、これから
アジャイル開発とTDDを半年間実践してみた顛末と、これからアジャイル開発とTDDを半年間実践してみた顛末と、これから
アジャイル開発とTDDを半年間実践してみた顛末と、これからKei Sawada
 
Tokyor14 - R言語でユニットテスト
Tokyor14 - R言語でユニットテストTokyor14 - R言語でユニットテスト
Tokyor14 - R言語でユニットテストYohei Sato
 
テスト駆動開発入門
テスト駆動開発入門テスト駆動開発入門
テスト駆動開発入門Shuji Watanabe
 
TDDBC Fukuoka Day1
TDDBC Fukuoka Day1TDDBC Fukuoka Day1
TDDBC Fukuoka Day1Takuto Wada
 
AWS Black Belt Tech シリーズ 2015 - AWS Data Pipeline
AWS Black Belt Tech シリーズ 2015 - AWS Data PipelineAWS Black Belt Tech シリーズ 2015 - AWS Data Pipeline
AWS Black Belt Tech シリーズ 2015 - AWS Data PipelineAmazon Web Services Japan
 

Viewers also liked (6)

TDDを実践してわかったTDDつまづくあるあると自分なりの乗り越え方まとめ
TDDを実践してわかったTDDつまづくあるあると自分なりの乗り越え方まとめTDDを実践してわかったTDDつまづくあるあると自分なりの乗り越え方まとめ
TDDを実践してわかったTDDつまづくあるあると自分なりの乗り越え方まとめ
 
アジャイル開発とTDDを半年間実践してみた顛末と、これから
アジャイル開発とTDDを半年間実践してみた顛末と、これからアジャイル開発とTDDを半年間実践してみた顛末と、これから
アジャイル開発とTDDを半年間実践してみた顛末と、これから
 
Tokyor14 - R言語でユニットテスト
Tokyor14 - R言語でユニットテストTokyor14 - R言語でユニットテスト
Tokyor14 - R言語でユニットテスト
 
テスト駆動開発入門
テスト駆動開発入門テスト駆動開発入門
テスト駆動開発入門
 
TDDBC Fukuoka Day1
TDDBC Fukuoka Day1TDDBC Fukuoka Day1
TDDBC Fukuoka Day1
 
AWS Black Belt Tech シリーズ 2015 - AWS Data Pipeline
AWS Black Belt Tech シリーズ 2015 - AWS Data PipelineAWS Black Belt Tech シリーズ 2015 - AWS Data Pipeline
AWS Black Belt Tech シリーズ 2015 - AWS Data Pipeline
 

Similar to ユニットテストの保守性を作りこむ, xpjugkansai2011

JavaScript/CSS 2015 Autumn
JavaScript/CSS 2015 AutumnJavaScript/CSS 2015 Autumn
JavaScript/CSS 2015 AutumnKoji Ishimoto
 
Unit test in android
Unit test in androidUnit test in android
Unit test in androidTatsuya Maki
 
Androidでテストってどないすんねん!
Androidでテストってどないすんねん!Androidでテストってどないすんねん!
Androidでテストってどないすんねん!akimichi Yamada
 

Similar to ユニットテストの保守性を作りこむ, xpjugkansai2011 (6)

20150302 java8 第一回_ラムダ式(1)
20150302 java8 第一回_ラムダ式(1)20150302 java8 第一回_ラムダ式(1)
20150302 java8 第一回_ラムダ式(1)
 
JavaScript/CSS 2015 Autumn
JavaScript/CSS 2015 AutumnJavaScript/CSS 2015 Autumn
JavaScript/CSS 2015 Autumn
 
tdd4cpp demo
tdd4cpp demotdd4cpp demo
tdd4cpp demo
 
Unit test in android
Unit test in androidUnit test in android
Unit test in android
 
Junit4
Junit4Junit4
Junit4
 
Androidでテストってどないすんねん!
Androidでテストってどないすんねん!Androidでテストってどないすんねん!
Androidでテストってどないすんねん!
 

More from H Iseri

フィーチャモデルの描き方
フィーチャモデルの描き方フィーチャモデルの描き方
フィーチャモデルの描き方H Iseri
 
PyAutoGUI等Pythonライブラリによる自動化支援
PyAutoGUI等Pythonライブラリによる自動化支援PyAutoGUI等Pythonライブラリによる自動化支援
PyAutoGUI等Pythonライブラリによる自動化支援H Iseri
 
クラシフィケーション・ツリー法入門
クラシフィケーション・ツリー法入門クラシフィケーション・ツリー法入門
クラシフィケーション・ツリー法入門H Iseri
 
レガシーコードとの付き合い方とテストでの話
レガシーコードとの付き合い方とテストでの話レガシーコードとの付き合い方とテストでの話
レガシーコードとの付き合い方とテストでの話H Iseri
 
探索的テスト入門
探索的テスト入門探索的テスト入門
探索的テスト入門H Iseri
 
組み込み開発でのシステムテスト自動化の一つの考え方(STAC)
組み込み開発でのシステムテスト自動化の一つの考え方(STAC)組み込み開発でのシステムテスト自動化の一つの考え方(STAC)
組み込み開発でのシステムテスト自動化の一つの考え方(STAC)H Iseri
 

More from H Iseri (6)

フィーチャモデルの描き方
フィーチャモデルの描き方フィーチャモデルの描き方
フィーチャモデルの描き方
 
PyAutoGUI等Pythonライブラリによる自動化支援
PyAutoGUI等Pythonライブラリによる自動化支援PyAutoGUI等Pythonライブラリによる自動化支援
PyAutoGUI等Pythonライブラリによる自動化支援
 
クラシフィケーション・ツリー法入門
クラシフィケーション・ツリー法入門クラシフィケーション・ツリー法入門
クラシフィケーション・ツリー法入門
 
レガシーコードとの付き合い方とテストでの話
レガシーコードとの付き合い方とテストでの話レガシーコードとの付き合い方とテストでの話
レガシーコードとの付き合い方とテストでの話
 
探索的テスト入門
探索的テスト入門探索的テスト入門
探索的テスト入門
 
組み込み開発でのシステムテスト自動化の一つの考え方(STAC)
組み込み開発でのシステムテスト自動化の一つの考え方(STAC)組み込み開発でのシステムテスト自動化の一つの考え方(STAC)
組み込み開発でのシステムテスト自動化の一つの考え方(STAC)
 

ユニットテストの保守性を作りこむ, xpjugkansai2011