XcodeでGoogle Test (gtest) を使えるようにセットアップする

Xcodeにはユニットテストを実行する機能があります。Xcodeから実行できるユニットテスト機能はXCTestフレームワークのチェック関数を使って、クラスやメソッドの戻り値が期待値通りになっているかをチェックします。チェック結果はXcodeの中でリスト表示されます。

XCTestはAppleプラットフォーム専用です。クロスプラットフォーム対応のライブラリを作っているときなどには、XCTestを使うよりも、クロスプラットフォーム対応のテストフレームワークを使用して、各プラットフォーム上で直接ユニットテストを実行できることが重要です。

クロスプラットフォーム対応のテストフレームワークの中にGoogle製のGoogle Test (gtest) があります。C++のテストフレームワークでmacOSやWindowsなど複数のプラットフォームに対応しています。

この記事では、 gtest をmacOS上でXcodeと組み合わせて使えるようにし、XCTestを使ったユニットテストと一緒にテストできるようにする方法を解説します。

スポンサーリンク

準備

この記事では、gtest をソースからビルドして使う方法を解説します。gtest のビルドには CMake が必要です。まず、 CMake をインストールしてください。インストール方法については、次の記事で解説しています。

関連記事

2020年4月18日 zshでのPATHの設定方法を追加しました。cmakeのオプションでインストール先を指定するように変更しました。 OpenCVはオープンソースの画像処理やマシンラーニングを行うためのライブラリです。高機能で多くの[…]

gtest をビルドする

gtest のコードはGitHubにありますので、GitHubからクローンするかダウンロードしてください。

GitHub

Googletest - Google Testing and Mocking Framework. Contribut…

CMakeの設定変更

gtestはCMakeで、Xcodeのプロジェクトを生成して、Xcodeを使ってビルドします。しかし、この記事を執筆している時点では、生成されるプロジェクトの設定に問題があり、ビルドが通りません。

生成されるプロジェクトでは、C11が有効になっていません。gtestをビルドするにはC11を有効化する必要があります。

CMakeLists.txtを開き、以下を追加します。Appleプラットフォーム上のときは、C++11を有効化するという設定です。

if (APPLE)
	SET(CMAKE_CXX_STANDARD 11)
	SET(CMAKE_CXX_STANDARD_REQUIRED on)
endif()

追加する場所は、enable_testing()という行の上くらいが良いと思います。編集した後のファイルは次のようになります。

# Note: CMake support is community-based. The maintainers do not use CMake
# internally.

cmake_minimum_required(VERSION 2.8.8)

if (POLICY CMP0048)
  cmake_policy(SET CMP0048 NEW)
endif (POLICY CMP0048)

project(googletest-distribution)
set(GOOGLETEST_VERSION 1.10.0)

if (CMAKE_VERSION VERSION_GREATER "3.0.2")
  if(NOT CYGWIN AND NOT MSYS)
    set(CMAKE_CXX_EXTENSIONS OFF)
  endif()
endif()

if (APPLE)
	SET(CMAKE_CXX_STANDARD 17)
	SET(CMAKE_CXX_STANDARD_REQUIRED on)
endif()

enable_testing()

include(CMakeDependentOption)
include(GNUInstallDirs)

#Note that googlemock target already builds googletest
option(BUILD_GMOCK "Builds the googlemock subproject" ON)
option(INSTALL_GTEST "Enable installation of googletest. (Projects embedding googletest may want to turn this OFF.)" ON)

if(BUILD_GMOCK)
  add_subdirectory( googlemock )
else()
  add_subdirectory( googletest )
endif()

プロジェクトの生成

ビルドするために必要なプロジェクトの生成などを行います。次のようにクローンしたフォルダの直下にmybuildというフォルダを作ります。

GoogleTest
├── BUILD.bazel
├── CMakeLists.txt
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── WORKSPACE
├── appveyor.yml
├── ci
├── googlemock
├── googletest
├── library.json
├── mybuild
└── platformio.ini

ターミナルでmybuildに移動します。

$ cd GoogleTest/mybuild

次のようにcmakeを使って、プロジェクトを生成します。指定しているオプションは、以下の通りです。適時変更してください。

  • pthreadを有効化
  • インストール先をusr/local/gtestに設定
  • Xcodeのプロジェクトを生成する
$ cmake -DGTEST_HAS_PTHREAD=1 -G Xcode -DCMAKE_INSTALL_PREFIX=/usr/local/gtest ../

C++11が有効化されているか確認する

プロジェクトの設定でC++11が有効化されていることを確認します。生成された`googletest-distribution.xcodeproj`を開きます。

プロジェクトのオプションを開き、gmockなどのターゲットのオプションを表示します。Build SettingsタブのOther C++ Flagsに`’-std=c++11’`があるかを確認します。

ビルドとインストール

xcodebuildを使ってビルドします。XcodeでGUIでビルドしても良いのですが、ここではターミナルで行います。また、インストール先を/usr/local/gtestに指定したので、書き込むためには管理者権限が必要です。そのため、sudo付きで実行します。

$ sudo xcodebuild -target install build

しばらくして、ビルドが成功すると、/usr/local/gtestにインストールされます。

/usr/local/gtest
├── include
│   ├── gmock
│   └── gtest
└── lib
    ├── cmake
    ├── libgmock_maind.a
    ├── libgmockd.a
    ├── libgtest_maind.a
    ├── libgtestd.a
    └── pkgconfig

Xcodeとgtestを連携させる

Xcodeのテストナビゲータに表示させるには、XCTestを使う必要があります。gtestもXCTestのテストケースと同じように表示させるには一工夫必要です。その一工夫を実装してくれたコードがOSSで公開されています。

GitHub

Google Test integration with Xcode. Contribute to mattsteven…

プロジェクトに必要ファイルを追加する

使用するのは、Bundle/GoogleTests.mです。このファイルをユニットテストバンドルのプロジェクトに追加します。

次に、ユニットテストバンドルのターゲットの設定で、「Build Settings」を開き、「Header Search Paths」と「Library Search Paths」に、インストールしたgtestのディレクトリを追加します。

以下の設定を書きます。

  • Header Search Paths : /usr/local/gtest/include
  • Library Search Paths : /usr/local/gtest/lib

ライブラリをリンクさせます。ユニットテストバンドルのターゲットに以下のライブラリを追加します。

  • libgtestd.a

プロジェクトに登録するのでも良いのですが、/usr/local/gtest/lib以下なので、少し面倒なら、次のようにOther Linker Flagsにオプション追加でも構いません。

  • Other Linker Flags : -lgtestd

テストを書く

確認するために簡単なテストコードを書いてみます。まずは、テスト対象のクラスを実装します。

// Counter.hpp
#ifndef COUNTER_HPP
#define COUNTER_HPP

class Counter {
private:
    int value_;
    
public:
    Counter();
    virtual ~Counter();
    
    void reset();
    void increment(int step = 1);
    void decrement(int step = 1);
    int value() const;
};

#endif /* COUNTER_HPP */
// Counter.cpp
#include "Counter.hpp"

Counter::Counter() : value_(0)
{
    
}

Counter::~Counter()
{
    
}

void Counter::reset()
{
    value_ = 0;
}

void Counter::increment(int step)
{
    value_ += step;
}

void Counter::decrement(int step)
{
    value_ -= step;
}

int Counter::value() const
{
    return value_;
}

テストケースを実装します。例えば、次のようなコードです。

// CounterTests.cpp
#include <gtest/gtest.h>
#include "Counter.hpp"

TEST(CounterTests, Initialize)
{
    Counter c;
    ASSERT_EQ(0, c.value());
}

TEST(CounterTests, Increment)
{
    Counter c;
    
    c.increment();
    ASSERT_EQ(1, c.value());
    
    c.increment(10);
    ASSERT_EQ(11, c.value());
}

TEST(CounterTests, Decrement)
{
    Counter c;
    
    c.decrement();
    ASSERT_EQ(-1, c.value());
    
    c.decrement(10);
    ASSERT_EQ(-11, c.value());
}

TEST(CounterTests, Reset)
{
    Counter c;
    
    c.increment();
    ASSERT_EQ(1, c.value());
    
    c.reset();
    ASSERT_EQ(0, c.value());
}

Xcodeでユニットテストを実行すると、テストナビゲータにXCTestで書いたテストと同様に項目が追加されて、テスト結果も表示されます。

スポンサーリンク
最新情報をチェックしよう!
>現役のプログラマーが書くプログラミング情報

現役のプログラマーが書くプログラミング情報

日々の開発の中での学びや分かったこと、調べたことなどを書いていくブログです。

CTR IMG