[Blender] GitHubとTravisCIを用いてBlenderアドオンのテストを自動化する

Blenderのアドオン開発に限らずにソフトウェアの開発全体に対して言えることですが、ソースコードを更新するたびにきちんと動作することを毎回確認するのは面倒ですよね。

本記事では、GitHubとTravis CIを用いてBlenderアドオンのテストを自動化する方法を紹介します。

# 前準備

本記事ではテスト自動化のために、CI（継続的インテグレーション）サービスの **Travis CI** とホスティングサービスの **GitHub** を利用します。
GitHubとTravis CIの使い方をここで説明すると長くなりますので省略します。
GitHubやTravis CIについてはウェブ上にたくさんの記事がありますので、各自参考にして以下のことができるようになるまで準備を進めてください。

1. GitHub
    * アカウント作成
    * リポジトリ作成
    * 作成したリポジトリへのpush
2. Travis CI
    * GitHubアカウントでログイン
    * GitHubで作成したリポジトリをテスト対象に設定

GitHubとTravis CIについては、例えば以下のサイトが参考になるでしょう。

* [ナウなヤングのためのgithub入門講座　-基本機能からdotfiles管理まで-](http://shim0mura.hatenadiary.jp/entry/20111212/1323660740)
* [Travis CI 入門：GitHub + Travis CI で継続的インテグレーション](http://tetsuwo.tumblr.com/post/44706350593/github-travis-continuous-integration)
* [GithubにあるリポジトリをTravis CI連携する手順 #junitbook](http://sue445.hatenablog.com/entry/2013/06/01/170607)

# ファイル構成

BlenderのアドオンをTravis CIでテストするためのファイル構成を以下に示します。

```
/    # リポジトリのルートディレクトリ
├ .travis.yml     # Travis CI用設定ファイル
├ test_addon.py   # テストするアドオン
├ run_tests.py    # 個別のテストを呼び出すスクリプト
├ test_1.py       # test_addon.pyのテストスクリプト
└ test_1.blend    # test_1.py用の.blendファイル
```

# アドオンの作成

テスト対象とするアドオンを作成します。ファイル名を ```test_addon.py``` としてください。
テスト対象のオペレーションクラスを1つ用意した単純なアドオンになっています。
なおアドオンの作り方については、以下の記事を参考にしてください。

* [[Blender] Blenderプラグインの作り方](http://qiita.com/nutti/items/a836391723bd28cd3e4c)

```py3:test_addon.py
import bpy

bl_info = {
    "name": "テストするアドオン",
    "author": "Nutti",
    "version": (1, 0),
    "blender": (2, 75, 0),
    "location": "UV Mapping > テストするアドオン",
    "description": "テスト対象のアドオン",
    "warning": "",
    "support": "TESTING",
    "wiki_url": "",
    "tracker_url": "",
    "category": "UV"
}


class TestOps(bpy.types.Operator):

    bl_idname = "uv.test_ops"
    bl_label = "テスト"
    bl_description = "テストするオペレーション"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        return {'FINISHED'}


def register():
    bpy.utils.register_module(__name__)


def unregister():
    bpy.utils.unregister_module(__name__)


if __name__ == "__main__":
    register()

```

# Travis CI用設定ファイル（.travis.yml）の作成

続いて、Travis CI用の設定ファイルを ```.travis.yml``` として保存します。
```.travis.yml``` の解説はコメントに記載しています。
基本的にはコメントの記載内容で理解できると思いますが、 ```.travis.yml``` の書き方に困った場合は以下の記事が参考になるでしょう。

* [【TravisCI】travis.ymlに書くあれこれ](http://qiita.com/oh_rusty_nail/items/157241b6cb5a304462fe)

```yaml:.travis.yml
# プログラミング言語の指定
# BlenderのアドオンはPythonで記述するためpythonを指定
language: python

# 使用するPythonのバージョン
# ★BlenderのPythonコンソールから利用されているPythonのバージョンを特定可能
python:
  - "3.4"

# install前に実行する処理
before_install:
  # 可能な限り最新のBlenderをインストール
  # パッケージマネージャー経由でインストールすることで、Blenderに依存しているパッケージを自動的にインストール（手動で依存するパッケージをインストールするのは手間がかかるため）
  - sudo apt-get update -qq
  - sudo apt-get install blender

# テスト実行の前準備
install:
  # 作業領域の作成し、移動
  - mkdir tmp && cd tmp
  # ★最新版のBlenderをダウンロード
  - wget http://mirror.cs.umn.edu/blender.org/release/Blender2.76/blender-2.76-linux-glibc211-x86_64.tar.bz2
  # ★ダウンロードしたBlenderを解凍
  - tar jxf blender-2.76-linux-glibc211-x86_64.tar.bz2
  - mv blender-2.76-linux-glibc211-x86_64 blender
  - rm blender-2.76-linux-glibc211-x86_64.tar.bz2
  - cd ..
  # ★アドオンをインストール（Blenderのバージョンに合わせて、ディレクトリを指定）
  - sudo ln -s ${PWD}/test_addon.py ${PWD}/tmp/blender/2.76/scripts/addons/test_addon.py

# テスト実行
script: python ${PWD}/run_tests.py ${PWD}/tmp/blender/blender
```

# テストスクリプトの作成

```.travis.yml``` の ```script``` に書かれたコマンドが実行されてテストが開始されます。

実行されるテストスクリプト ```run_tests.py``` を作成します。
これは、個別のテストを呼び出す大元のテストスクリプトになります。
テストスクリプトは、Blenderのアドオンの開発言語であるPythonで書きます。

UI表示をなくすため、Blenderをコマンドラインで実行するところがポイントです。
Blenderをコマンドラインから実行するときに指定できるオプションは、以下のサイトから確認することができます。

http://wiki.blender.org/index.php/Doc:JA/2.6/Manual/Render/Command_Line

```py3:run_tests.py
import sys
import subprocess

if len(sys.argv) != 2:
    exit(-1)

blender_path = sys.argv[1]     # Blender本体のパス

addon_name = 'test_addon'      # テストするアドオン
blend_file = 'test_1.blend'    # テスト用に作成した.blendファイル
src_file = 'test_1.py'         # 個別のテスト用スクリプト

# 個別のテスト用スクリプト（test_1.py）を実行
# 実行されるコマンド： blender --addons test_addon --factory-startup -noaudio -b test_1.blend --python test_1.py
# オプション: 
#   --addons: test_addonを有効化
#   --factory-startup: startup.blendファイルを読み込まない
#   -noaudio: サウンドの無効化
#   -b: UIなしBlender起動
#   blend_file: 読み込む.blendファイル
#   --python: src_fileに指定したPythonスクリプトを実行
subprocess.call([blender_path, '--addons', addon_name, '--factory-startup', '-noaudio', '-b', blend_file, '--python', src_file])

```

続いて ```run_tests.py``` から呼ばれる、個別のテスト用スクリプト ```test_1.py``` を作成します。
テストの方法はいろいろありますが、Pythonのテストフレームワークであるunittestモジュールを利用するのが手っ取り早いでしょう。

http://docs.python.jp/2/library/unittest.html


```py3:test_1.py
import unittest    # Pythonのテストフレームワーク
import bpy

# テストセット
class TestAddon(unittest.TestCase):
    # アドオンが正常に有効化されたことを確認
    def test_addon_enabled(self):
        self.assertIsNotNone(by.ops.uv.test_ops)

    # アドオンを実行して正常終了したことを確認
    def test_execute(self):
        result = boy.ops.uv.test_ops()
        self.assertSetEqual(result, {'FINISHED'})


# テストセットの作成
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestAddon)
# テスト実行
unittest.TextTestRunner().run(suite)

```

最後に、Blender起動時の状態で.blendファイルを ```test_1.blend``` として保存しましょう。
```test_1.blend``` は、テスト実行時に利用する.blendファイルです。

実際にテストする場合は、実行したいテストに合わせて.blendファイルを作成する必要があります。
今回は簡単のため、Blender起動時の状態を保存しました。

# テストの実行

テスト対象にしたリポジトリへ ```push``` することで自動的にテストが実行されます。

```sh:run_test.sh
$ git push
```

![addon_test_1.png](https://qiita-image-store.s3.amazonaws.com/0/38888/e10c5860-b71f-4f1f-2be6-40ec008c9997.png)


# テスト結果の確認

Travis CIのサイトからテストの実行結果を確認してみましょう。
テストがうまくいっていれば以下のような画面になっていると思います。

![addon_test_2.png](https://qiita-image-store.s3.amazonaws.com/0/38888/a47f3be4-25db-a8b9-f45a-e581eba23aca.png)

テスト実行時の内容の詳細もWeb上から確認することができ ```.travis.yml``` に記載した処理が実行されていることがわかります。
今回は ```test_addon_enabled``` と ```test_execute``` の2つのテストを実行しているため ```Ran 2 tests in 0.001s``` と表示されています。
その後にテストが通ったことを示す ```OK``` が出力されているため、テストが無事に通ったことがわかります。

![addon_test_3.png](https://qiita-image-store.s3.amazonaws.com/0/38888/85a9986b-e2b4-c8ea-e23c-0e247e66f48a.png)

テストはリポジトリにpushする度に行われるため、アドオンを更新した時に問題ないかどうかを手作業で確認する必要がなくなります。
テストの手間と手作業による確認ミスを防ぐことができ、アドオン開発者は開発に集中することができますので、自動化できる部分はどんどん自動化してしまいましょう。

# 参考資料

* [Automatic Blender Addon Testing with TravisCI](http://www.anzui.de/en/blog/2015/05-21)
* [ナウなヤングのためのgithub入門講座　-基本機能からdotfiles管理まで-](http://shim0mura.hatenadiary.jp/entry/20111212/1323660740)
* [Travis CI 入門：GitHub + Travis CI で継続的インテグレーション](http://tetsuwo.tumblr.com/post/44706350593/github-travis-continuous-integration)
* [GithubにあるリポジトリをTravis CI連携する手順 #junitbook](http://sue445.hatenablog.com/entry/2013/06/01/170607)
* [[Blender] Blenderプラグインの作り方](http://qiita.com/nutti/items/a836391723bd28cd3e4c)
* [【TravisCI】travis.ymlに書くあれこれ](http://qiita.com/oh_rusty_nail/items/157241b6cb5a304462fe)
* http://wiki.blender.org/index.php/Doc:JA/2.6/Manual/Render/Command_Line
* http://docs.python.jp/2/library/unittest.html