14 Oct 2013, 13:28

『Modern C++ with TDD』学習メモ(Chapter2-5)

Modern C++ Programming with Test-Driven Development: Code Better, Sleep

Better

体育の日の祝日なので、図書館とカフェにこもってベンキョしてました。そんな体育の日もオツだよね。というわけで、今日勉強した記録を淡々とメモします。

今日は、『Modern C++ Programming with Test-Driven Development』の前半を読みました。これからあんまし時間がとれなくなる気がするので、後半はお正月休みあたりか。

各章の概略

  • Chapter1・・・ツールの準備について。
  • Chapter2・・・TDDの実践方法をsampleとともに、解説される。ここでは、GoogleMockをつかうものの、中身としてはGoogleTestの使い方解説。TDDを知らない初心者向けに丁寧に書いてある。リファクタリングの方法なども、sampleとともに、体験できる。けっこう優しめで丁寧。
  • Chapter3・・・『レッド・グリーン・リファクタリング』にはじまるTDDの思想や原則、規律について書いてある。Webや書籍ですでにいろいろと言われていることをまとめているだけなので、とりわけ目新しいことはない。
  • Chapter4・・・GoogleMockの細かい使い方など。テスト。フィクスチャ、テストのフィルターやパラメタライズドテストの方法が解説される。HamcrestやASSERT_THATがmodernなのだ!と強調される。また、例外のテストや浮動小数点数のテストなど、細かいTipsとか。
  • Chapter5・・・テスト・ダブルの紹介。ここでついに、GoogleMockが登場。まずは、マニュアルでモックをつくらせて、そのあとにGoogleMockでモックをつくり『ほ~ら、コンナに簡単にできちゃうんだぞ~』とさとされる。cURL、JSONCPPなどのサードパーティをつかって、それらとの依存関係を取り除く方法が紹介される。

Study Memo

以下、新しく知ったことを忘れないためのStudy Memo。なので、自分が知っていることは省略。

ASSERT_EQと ASSERT_THAT

いままで、テスト結果の検証には『ASSERT_EQ』しか利用してこなかったけれども、この本では 『ASSERT_THAT』を利用している。理由は、テストコードの可読性が高まるから。

比較してみる。 『1+1=2』( (1+1) equals to 2 )。

ASSERT_EQ( 2, (1+1) );

これを、ASSERT_THATで書きなおすと以下のようになる。

ASSERT_THAT( (1+1), Eq(2) );

なるほど、英語の文の並びと同じになる。 Assert that 1+1 equals to 2.

ASSERT_EQからASSERT_THATを利用しているところが、まずモダン。

Test Fixtureでのクラス生成はポインタで

クラスをフィクスチャ間で共有するには、どうすればいいか、いままでワカラなかった。こうすればよい。

#include "gmock/gmock.h"
#include "RetweetCollection.h"
#include "Tweet.h"

#include 

using namespace ::testing;
using namespace std

class ARetweetCollectionWithOneTweet: public Test {
public:
   RetweetCollection collection;
   shared_ptr tweet;

   void SetUp() override {
      tweet = shared_ptr(new Tweet("msg", "@user"));
      collection.add(*tweet);
   }
};

TEST_F(ARetweetCollectionWithOneTweet, IgnoresDuplicateTweetAdded) {
   Tweet duplicate(*tweet);
   collection.add(duplicate);

   ASSERT_THAT(collection.size(), Eq(1u));
}

Classの宣言に、shared_ptrを利用して、SetUp()でメモリを動的に獲得する。

Hamcrest Assertion

従来のAssertion(expect_eqとか)では、一つの宣言で一つのことしか検証できなかった。

しかし、モダンなHamcrest Assertionだと、Matcherを利用し、一つの宣言で複数のことを検証できる。

ASSERT_THAT(actual,
    AllOf(StartsWith("al"), EndsWith("ha"), Ne("aloha")));

GoogleMockはC++でHamcrestが利用できるxUnitなので、こういう方法も紹介されている。

Parameterized Test

複数のテストケースをまとめて実行できるというもの。TDDというよりは、スプレッドシートにかかれた仕様を検証するようなときに必要そうなテストの書き方。

#include "gmock/gmock.h"
using namespace ::testing;

struct Sumcase {
  int a, b, expected;
  Sumcase(int anA, int aB, int anExpected)
    : a(anA), b(aB), expected(anExpected) {}
};

class AnAdder: public TestWithParam {
};

class Adder {
public:
  static int sum(int a, int b) {
    return a + b;
  }
};

TEST(AnAdder, GenerateASumFromTwoNumbers) {
  ASSERT_THAT(Adder::sum(1, 1), Eq(2));
}

TEST_P(AnAdder, GenerateLotsOfSumsFromTwoNumbers) {
  Sumcase input = GetParam();
  ASSERT_THAT(Adder::sum(input.a, input.b), Eq(input.expected));
}

Sumcase sums[] = {
  Sumcase(1,1,2),
  Sumcase(1,2,3),
  Sumcase(2,2,4)
};

INSTANTIATE_TEST_CASE_P(BulkTest, AnAdder, ValuesIn(sums));

Test Double、Mock、Stub、Spy、Fake

これは、この本の本題ではないけれども、メモしとく。

  • Test Double・・・テストのために本番用コードと置き換わり、本番用コードをエミュレートするもの
  • Stub・・・ハードコーディングされた値を返すTest Double
  • Spy・・・テストの後の検証のために、オブジェクトに送られた情報をキャッチするTest Double
  • Mock・・・自分で検証機能をもつTest Double
  • Fake・・・本番用クラスを簡易版実装したTestDouble

19 Aug 2013, 15:32

夏休みの自由研究 『Console Karajan』

夏休みが4日間あったので、なにか自由研究をしてみようと思いました。

Kinectを使ってクラシック音楽を操るソフトをつくろうとしたのだけれども、結局Kinectをつかいこなすまで開発が進まなかったorz。というわけで、コンソールバージョンの日記でも。

[//www.youtube.com/embed/-9tmgcL0V-Y?rel=0]

実は、もともとゴールデンウィークにつくってたものだけれども、ゴールデンウィークの3日間で完成せず、夏休みの4日間でも完成せず。もう1週間もかけてるのに、一向に開発はすすまず。はたして、次はお正月か?

音源の制御には、VLCのAPIを利用。

テンポの変更検出は、4拍子ごとに実施しているけど、これだと精度が悪すぎた。また、急激にテンポを変更すると、きいていて違和感が。今後の課題。

こっちが本物のカラヤン。カックイイ(・∀・)

[//www.youtube.com/embed/FJ96i-m6cBk?rel=0]

ちなみに、テストはGoogleTest/GoogleMockを使ってバリバリ実施。むしろ、こっちが大変だった。GoogleTestはファイル操作系のwindows APIと相性が悪くて、これだけで半日潰れて、そのままうつになって、一日潰れた。

[//www.youtube.com/embed/lzsrTv3UA-I?rel=0]

02 May 2013, 16:41

Visual Studio 2012に GoogleMockを導入したメモ

Visual StudioにGoogleMockを導入する手順も忘れないようにメモしながら入れてみようと思います。GoogleTestはGoogleMockの中に含まれるので、GoogleMockを入れれば、GoogleTestもついてくる。一石二鳥、早起きは三文の得、結構毛だらけ猫灰だらけだ。

導入環境

  • Windows 7
  • Visual Studio Express 2012  for Windows Desktop
  • GoogleMock 1.6.0

GoogleMockをダウンロード

GoogleMockをダウンロードしてきて、適当な場所に置きます。

https://code.google.com/p/googlemock/

Visual StudioでGoogleMockをビルド

Visual StudioでGoogleMockをビルドします。

まずは、msvc/2010配下に移動してフォルダの読み取り専用属性を外します。右クリックから[プロパティ] > [読み取り専用]のチェックを外す。

次に、gmock.slnをVisual Studioで起動します。Visual Studioの変換ウィザードが立ち上がり2010が2012用のプロジェクトに変換されるはず。

上のツールバーから[ビルド] > [ソリューションのビルド]でビルドまたは、F7で。そうすると、エラーが出まくるはず(´・ω・`)

以下のサイトに、解説方法が載っている。感謝しながらヘッダファイルを修正しよう。gmockだけど、gtestのファイルを修正する。

ブログズミ: Visual Studio 11 Beta で Google Test を使う

gmock\gtest\include\gtest\internal\gtest-port.h

ただし、GoogleTestならばこれでうまく行くけれども、GoogleMockは軽薄な奴なので、そうはいかない。追加で修正。

ソリューションエクスプローラに並んでいるプロジェクト(gmock,gmock_main,gmock_test)のプロパティを右クリックで開き、[構成プロパティ] > [C/C++] > [プリプロセッサ] >[プリプロセッサの定義]を選択して、以下のdefineを追加する。

_VARIADIC_MAX=10

image

gmock\msvc\2010\Debug\gmock_test.exeができるので、とりあえず動かしてみて、テストが走ればコンパイル成功。以下のライブラリが作成されます。

  • gmock.lib
  • gmock_main.lib

GoogleMockを使いたいプロジェクトの設定

GoogleMockを使いたいプロジェクトをVisual Studioで起動します。プロジェクトのプロパティを以下のように修正。gtestはgmockに含まれるので、ライブラリは必要ないことに注意。

  • gmockとgtestのインクルードディレクトリを設定 
    • C/C++ -> 全般 -> 追加のインクルードディレクトリ
      • \gmock-1.6.0\include
      • \gmock-1.6.0\gtest\include
  • gmock ライブラリを追加(gtestライブラリの代わり)
    • リンカー -> 全般 -> 追加のライブラリディレクトリ
      • \gmock-1.6.0\msvc\2010\Debug
    • リンカー-> 入力 -> 追加のライブラリ
      • gmock.lib
      • gmock_main.lib
  • ランタイムライブラリの修正
  • C/C++ -> コード生成-> ランタイムライブラリ
  • マルチスレッド デバッグ (/MTd)

また、_VARIADIC_MAX=10もプリプロセッサに追加する。

Debug用のメイン関数に をインクルードする。また、main関数に、    ::testing::InitGoogleMock(&argc, argv);を追加。

#include "stdafx.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>

 
int _tmain(int argc, _TCHAR* argv[])
{
    ::testing::InitGoogleTest(&argc, argv);
 ::testing::InitGoogleMock(&argc, argv);
    return RUN_ALL_TESTS();
}

サンプルコードまで書こうとおもったけど、疲れたので今日は終わり。参考リンクを下にいろいろ貼っておきます。

参考

03 Feb 2013, 01:00

GoogleTestとEclipseのGDB機能の組み合わせが最強だった件

Eclipse CDTでデフォルトで付いているグラフィカルなGDB用のインタフェースと、GoogleTestなどのxUnitをあわせて利用するとデバッグが捗ったので、メモ。

基本は動的、バグったら静的

方法は以下の通り。

  1. GoogleTestを使ってテストを書いて実行。
  2. テスト失敗したら、失敗したテストケースでブレイクポイントをはる。
  3. GoogleTestを再実行して、ブレイクしたところからステップ実行して、テスト失敗の理由を調査。

基本的には、GoogleTestで自動テストを書いていく。
しかし、テストが失敗し、その原因がよくわからないときはGDBでメモリの値の変化をステップごとに追いながらデバッグをするというスタンスだ。

EclipseのGDB機能はスゴく高性能で、
構造体のネスト構造まで、スケスケ丸見えなのだ(下品 (・∀・)ニヤニヤにや)

キーバインドでパースペクティブを行ったり来たり

キーバインド的には、

GoogleTest実行時 =>「Ctrl+ F11」
GDB起動時          => 「F11」

というようにしている。すると、実行によってEclipseのパースペクティブが[C/C++]と[デバッグ]で切り替えることができる。

設定が必要な場合は、
[ウィンドウ] > [設定] > [実行/デバッグ] > [パースペクティブ]から[C/C++ Application]を選択し、適切に設定すること。

また、ブレークポイントを設定することで、自動的に実行時にはデバッグパースペクティブに切り替えることもできる。
[ウィンドウ] > [設定] > [実行/デバッグ] から設定。(多分、これはデフェルト設定)

セグメンテーション違反対策に効果バツグン!

個人的にとてもいいなと感じたのは、セグメンテーション違反するとその直前でGoogleTestの実行処理を止めることができること。

テストコードがないコードに修正をいれるのは怖いので、まずテストを書いてから修正を入れるようにしているが、このレガシーコードへのテストを書く際に、メモリ獲得を忘れて画面が真っ赤になることがすごくたくさんあるのだ!

この潰し込みが大変で、テストを書くことを諦めることが往々にしてある。
しかし、このgdbを使った方法をとれば、驚くほど効率が上がった。

まとめ

今まで、gdbを積極的には使って来なかった。
(使い方をあまり知らなかったという方が正しいかもしれない)
手動テストなんてありえない!という偏見があったのかもしれない。

物事に偏見をもってはいけないというお話でした。

チャンチャン( ゚∀゚ )

26 Jan 2013, 00:44

[Eclipse CDT]セグメンテーション違反した箇所をGDBで特定する

Eclipse+Cygwin環境でデバッグするとき、いつもはGoogleTestを使っている。

GoogleTestを実行してセグメンテーション違反をすると、Windowsは以下のエラーを返す。

 [main] sample 10968 exception::handle: Exception: STATUS_ACCESS_VIOLATION
1714 [main] sample 10968 open_stackdumpfile: Dumping stack trace to sample.exe.stackdump

例:こんなお粗末ソース

#include

int add(int x, int y)
{
int z;
char *p;

z = x + y;
*p = 1; /* ここでセグメンテーション違反 */
return z;
}

こんなとき、Eclipseの画面からGDBを起動して、どこで落ちたかを調べると便利だったので、メモ。

環境

  • Eclipse 4.2 Juno
  • GDB 7.5
  • Cygwin 1.7.17-1

EclipseでGDBを利用するための設定

コンパイルオプション

まずは実行ファイルを作るときにコンパイルオプションで以下を追加。

CPPFLAGS += -g -O0

-g : GDB用のデバッグ情報を実行ファイルに含める。

-Oo : コンパイラに最適化をさせない。

ルックアップパスの設定

デバッグ・パースペクティブにソースが現れないときは、ソースのパスが設定されていない。

Can't find a source file at : hogehoge...

[ウィンドウ] > [設定] > [C/C++] > [デバッグ] > [ソース・ルックアップ・パス] から追加したいソースがあるフォルダを追加する。

GDBを実行してみる

デバッグ・パースペクティブからF11を実行できればOK。

Defaultではmainでbreakするように設定されているので、[再開]F8する。

すると、STATUS_ACCESS_VIOLATIONが発生した場所まで移動して、

ソースを表示してくれる。

image

まとめ

今回、xUnitとGDBを組み合わせることでデバッグがさらに効率的になるのではと思い、記事にしてみた。

この方法の前は、いちいちテストやソースにprintやexitを仕込んでいたが、始めっからgdbを使えばよかったなと、今頃ながら気づいたのだった。

xUnitでテストするようになってから、さすがにもう手動でのテストをする気にはなれないが、こんな組み合わせもいいかもしれない。

Eclipse+Cygwin環境でデバッグするとき、いつもはGoogleTestを使っている。

GoogleTestを実行してセグメンテーション違反をすると、Windowsは以下のエラーを返す。

ツꀀツꀀツꀀツꀀツꀀ 1 [main] sample 10968 exception::handle: Exception: STATUS_ACCESS_VIOLATION
1714 [main] sample 10968 open_stackdumpfile: Dumping stack trace to sample.exe.stackdump

例:こんなお粗末ソース

#include

int add(int x, int y)

{

int z;

char *p;

z = x + y;

*p = 1;ツꀀツꀀツꀀ /* ここでセグメンテーション違反 */

return z;

}

こんなとき、Eclipseの画面からGDBを起動して、どこで落ちたかを調べると便利だったので、メモ。

環境

  • Eclipseツꀀ 4.2 Juno
  • GDB 7.5
  • Cygwin 1.7.17-1

EclipseでGDBを利用するための設定

コンパイルオプション

まずは実行ファイルを作るときにコンパイルオプションで以下を追加。

CPPFLAGS += -g -O0

-g : GDB用のデバッグ情報を実行ファイルに含める。

-Oo : コンパイラに最適化をさせない。

ルックアップパスの設定

デバッグ・パースペクティブにソースが現れないときは、ソースのパスが設定されていない。

Can’t find a source file at : hogehoge…

[ウィンドウ] > [設定] > [C/C++] > [デバッグ] > [ソース・ルックアップ・パス] から追加したいソースがあるフォルダを追加する。

GDBを実行してみる

デバッグ・パースペクティブからF11を実行できればOK。

Defaultではmainでbreakするように設定されているので、[再開]F8する。

すると、STATUS_ACCESS_VIOLATIONが発生した場所まで移動して、

ソースを表示してくれる。

image

まとめ

今回、xUnitとGDBを組み合わせることでデバッグがさらに効率的になるのではと思い、記事にしてみた。

この方法の前は、いちいちテストやソースにprintやexitを仕込んでいたが、始めっからgdbを使えばよかったなと、今頃ながら気づいたのだった。

xUnitでテストするようになってから、さすがにもう手動でのテストをする気にはなれないが、こんな組み合わせもいいかもしれない。

21 Oct 2012, 12:35

『cdt-tests-runner』GoogleTestの結果をEclipse CDTから見るプラグイン

自分は、Eclipse CDTからGoogleTestを利用している。
Eclipse CDTから GoogleTestの結果を見るプラグインを見つけたので、紹介。

[http://www.youtube.com/embed/vObiKSSNJEY]

 

JUnit ViewerのCDT版『cdt-tests-runner』

プラグインの名前は『cdt-tests-runner』。公式サイトは以下。

https://github.com/xgsa/cdt-tests-runner/wiki/Tutorial

GoogleTestだけでなく、Boost Test, Qt Testにも対応している。

Eclipse CDT 8.1 からは、デフォルトで搭載されているらしい。
が、自分のCDT 8.1には入っていなかったので、手動でダウンロードした。
以下のパスを[ヘルプ] > [新規ソフトウェアのインストール] > [作業対象] に貼り付けて、C/C++ Test Runnerをインストール。

https://raw.github.com/xgsa/cdt-tests-runner/tests_runner_demo/testsrunner/org.eclipse.cdt.testsrunner-updatesite/site.xml

image

cdt-tests-runnerの設定方法

インストールできたら、GoogleTestを走らせたいプロジェクトの[実行の構成]を見る。
C/C++ Unitという新たな項目を選択して、実行構成を新規作成。

GoogleTestを利用するためには、[C/C++ Testing]タブを開いて、Tests RunnerでGoogle Tests Runnerを選択する。

image

[実行]を選択すると、テストが走り、実行結果が表示される。

実行結果

image

失敗したテストをクリックすると、そのテストまでジャンプできるところが嬉しい。
これはEmacsではできるよと書いてあったが、Eclipseでもしたかった。

Emacs で直接,失敗した行に移動するにはどうすればよいでしょうか? 窶錀 GoogleTests

Eclipse のプラグインでなければ、Guiterもあるよ

Eclipseのプラグインにこだわりがなかったり、Eclipseユーザでなければ、『gtest-gbar(Guiter)』というツールをつかうという選択肢もある。

http://code.google.com/p/gtest-gbar/

これならば、Visual Studioユーザでもレッド・グリーンが楽しめる。

今までは、自分もこっちを利用していた。
エラーしたときのメッセージ表示の欄が広くて見やすいので、またこっちに戻るかも。

22 Sep 2012, 01:02

JenkinsでGoogleTestのテスト結果を表示する方法を調べてみた。

GoogleTest(gtest)のテスト結果をJenkinsで表示する方法を調べてみた。

GoogleTestで出力されるXML出力結果はJUnitのフォーマット(junitreport Ant タスク)

にもとづいているため、Jenkinsに取り込んで解析することができるらしい。

GoogleTestのテスト結果をXML形式で出力する

テスト実行時に、以下のオプションとともに実行するとxML形式でテスト結果が出力される。 –gtest_output=xml:(ファイル名)がオプションだ。

[text](プログラム).exe 窶堵test_output=xml:(出力ファイル名).xml[/text]

こんな感じでXML出力される。


<testsuites tests="3" failures="0" disabled="0" errors="0" time="0.012" name="AllTests">
  <testsuite name="MockNumTest" tests="3" failures="0" disabled="0" errors="0" time="0.006">
    <testcase name="return1" status="run" time="0" classname="MockNumTest" />
    <testcase name="return2" status="run" time="0" classname="MockNumTest" />
    <testcase name="return3" status="run" time="0" classname="MockNumTest" />
  </testsuite>
</testsuites>

XML形式のテスト結果をJenkinsで表示する

次はjenkinsの設定。ジョブの設定画面を開く。

[プロジェクトの高度なオプション] > [カスタムワークスペースの使用]

にチェックを入れて、テスト出力ファイルのディレクトリの指定。

[ビルド]を選択して、ビルドを実行するための方法を選択。

ここでは、Windowsバッチコマンドで実行する。

[text]

cd “C:\Users\hogehoge\Dropbox\src\mock_study”

make clean

make

target.exe –gtest_output=”xml:test_result.xml”

[/text]

Windowsバッチコマンドがでmakeができないときは、

WindowsサービスでJenkinsを立ち上げるのをやめるとよい。

参考:WindowsバッチファイルをJenkinsで起動したらネットにアクセスできないツꀀ

[ビルド後の処理] > [JUnitテスト結果の集計]を選択。テスト結果ファイル名を入力。

image

テスト出力結果

こんな感じで出力された。

image

参考リンク

GoogleTest – 上級ガイド – XMLレポート