More Related Content
Similar to Trac Plugin Developement with Jenkins
Similar to Trac Plugin Developement with Jenkins (20)
Trac Plugin Developement with Jenkins
- 1. Jenkinsと一緒にTracプラグイン開発
-UT/IT自動化のコツ-
2011年5月20日
株式会社NTTデータ
Copyright © 2011 NTT DATA CORPORATION 技術開発本部 ALMソリューションセンタ
- 2. アジェンダ
1. 自己紹介
2. Trac Plugin開発 with Jenkins
1. 開発環境説明
2. 環境準備(ジョブ作成など)
3. コーディング
4. 単体テスト
5. 結合テスト
3. 最後に
Copyright © 2011 NTT DATA CORPORATION 1
- 3. 自己紹介
名前:和田 貴久
Twitter ID:@wadatka
所属:NTTデータ
何ができる?:
入社以来、Python道を攻略中です。
それ以前は、データマイニングの研究や.netでの開発をやっていました。
今の仕事:
社内向けの開発支援ツールの開発
各プロジェクトへの開発支援ツールの導入・普及活動
Copyright © 2011 NTT DATA CORPORATION 2
- 5. Trac Plugin開発 with Jenkins
■ 弊社で行ってきたSDワークベンチ(開発支援ツール)の開発で、Jenkinsをどのように活
用してきたか紹介します。
ポイント
• 品質を担保するため、一定以上のテスト密度が必要。
• バグ修正時の再テストの量が膨大
• リリース毎のテストの量が膨大
⇒Jenkinsで自動化して効率的に!
ポイント
• ゼロ機能リリースを実践!(ZFR:Zero-Feature Release)
⇒開発の最初に機能はないがリリースできる状態を用意
⇒以降の開発の進捗がわかりやすくなる!
Copyright © 2011 NTT DATA CORPORATION 4
- 6. Trac Plugin開発(開発環境)
Tracプラグインの開発は、下記の開発環境とサーバ構成で行いました。
開発者端末
• 実行結果(メール、IRC、・・・)
• レポート
• コミット
• バグチケット • チェックアウト/アップデート
単体テストジョブ
CIサーバ Seleniumジョブ
• チェックアウト/
アップデート
• Java
• Python
• ポーリング
デプロイジョブ
ポイント
デプロイサーバ(Slave)
• CIサーバやデプロイサーバは、ジョブ
の実行で負荷がかかるので、 • Java
Trac・Subversionと分けて構築しました! • Python
• Trac
Copyright © 2011 NTT DATA CORPORATION 5
- 7. Trac Plugin開発(開発準備)
「何を作るか」「どのように作るか」は、決まっているものとします。
Jenkinsとコラボレーションするための準備をします。
• 準備は、次の2ステップで行います。
1. Subversionへの雛型フォルダ・ファイルのインポート
• プラグイン本体コード
コードの中身はなくてもOK!
• 単体テストコード
まずは、フォルダと空ファイルだけでもインポート
• Seleniumコード
2. Jenkinsのジョブの作成
• 単体テストジョブ
インポートしたコードのチェックアウトと実行を行うジョブを作成
• デプロイジョブ
結果は空だが、いつでも実行できるジョブを用意
• Seleniumジョブ
ポイント
• CIやるならコーディング前からジョブを作るべし!
• ZFR を実践!!!
Copyright © 2011 NTT DATA CORPORATION 6
- 9. Trac Plugin開発(単体テストジョブ)
• 流れ:チェックアウト⇒単体テストコード実行⇒結果の変換
• Jenkinsプラグイン:Cobertura Plguin、violations
• その他のツール:ant、python-coverage、pylint、nose
CIサーバー(Masterマシン)
リポジトリ
ワークスペース 単体テストジョブ
Ant •チェックアウト
チェックアウト
HelloWorldPlugin •Ant実行 Antで定義した処理
• ワークスペースの初期化
•結果保存 • プラグインのインストール
Result
• 単体テストコードの実行
• テスト結果の集計
チェックアウト • カバレッジの集計
• Pylintでの解析
• 集計・解析結果の変換
ポイント
• 出てきた結果は視覚化したい!!!
⇒各種プラグインで読み込むために変換スクリプト
を実装。
Copyright © 2011 NTT DATA CORPORATION 8
- 10. Trac Plugin開発(単体テストジョブでの利用ファイル)
単体テストジョブで実行したAntファイル
<?xml version="1.0"?> (続き)
<project name="pythonUnitTest" default="report">
<property name="project.name" value="pythonUnitTest"/> <!-- report -->
<target name="report" depends="test"> レポート変換
<!-- Properties for all source file folders --> <!-- report of nose -->
<property name="src.dir" value="plugins"/> <exec dir="${basedir}" executable="python.exe">
<arg line="converter.py test ${src.dir}¥nosetest.xml ${result.dir}¥nosetest.xml"/>
<property name="result.dir" value="result"/> </exec>
<property name="result.test" value="${result.dir}/nosetest.xml"/>
<property name="result.pylint" value="${result.dir}/pylint.txt.raw"/> <!-- report of coverage(xml) -->
<property name="result.coverage" value="${result.dir}/coverage.xml"/> <exec dir="${src.dir}" executable="coverage.exe">
<property name="result.coverage.dir" value="${result.dir}/coverage"/> <arg line="xml --omit=*__init__.py,*setup.py,*¥*¥tests¥*.py"/>
</exec>
<!-- init -->
<target name="init">
初期化 <exec dir="${basedir}" executable="python.exe">
<delete dir="${result.dir}"/> <arg line="converter.py test ${src.dir}¥coverage.xml ${src.dir}¥coverage2.xml"/>
<mkdir dir="${result.dir}"/> </exec>
<mkdir dir="${result.coverage.dir}"/>
<exec dir="${src.dir}" executable="coverage.exe"> <!-- report of coverage(html) -->
<arg line="-e"/> <exec dir="${src.dir}" executable="coverage.exe">
</exec> <arg line="-b -i -d ..¥${result.coverage.dir} --omit=*__init__.py,*setup.py,*¥*¥tests¥*.py"/>
</target> </exec>
<!-- test --> <!-- report of pylint -->
<target name="test" depends="init"> テスト <exec dir="${src.dir}" executable="pylint.bat" output="${result.pylint}">
<exec dir="${src.dir}" executable="nosetests.exe"> <arg line="-f parseable -i y . --output-format=parseable --
<arg line="-i .*¥.*¥tests¥*.py --with-xunit --xunit-file=nosetest.xml --with-coverage"/> ignore=decoder.py,report_editor.py,setup.py,tests"/>
</exec> </exec>
</target> <exec dir="${basedir}" executable="python.exe">
<arg line="converter.py pylint ${result.dir}¥pylint.txt.raw ${result.dir}¥pylint.txt"/>
</exec>
</target>
(続く・・・) </project>
Copyright © 2011 NTT DATA CORPORATION 9
- 11. Trac Plugin開発(単体テストジョブでの利用ファイル)
単体テストジョブで実行したAntファイル
# -*- coding: utf-8 -*- (続き)
import codecs
import os argvs = sys.argv
import re argc = len(argvs)
import sys
if (argc != 4):
global _workspace_path print 'Usage: python %s mode input_file output_file' % argvs[0]
_workspace_path = os.path.dirname(os.path.abspath(__file__))
if argvs[1] == 'test':
print _workspace_path convert_character_code(argvs[2], argvs[3])
elif argvs[1] == 'pylint':
def convert_character_code(input_file, output_file): convert_escape_character(argvs[2], argvs[3])
input = codecs.open(input_file, 'r', 'shift_jis')
output = codecs.open(output_file, 'w', 'utf-8')
for line in input: 単体テスト結果、
output.write(line)
カバレッジの変換
output.close()
input.close()
print output_file + ' is generated from ' + input_file
def convert_escape_character(input_file, output_file):
input = open(input_file, 'r')
output = open(output_file, 'w',)
for line in input:
if '__init__.py' in line: Pylintの結果の変換
continue
else:
output.write(re.sub('¥¥¥¥', '/', line))
output.close()
input.close()
print output_file + ‘ is generated from ’ + input_file (続く・・・)
Copyright © 2011 NTT DATA CORPORATION 10
- 14. Trac Plugin開発(デプロイジョブ)
• 流れ:チェックアウト⇒プラグインインストール⇒Trac再起動
• Jenkinsプラグイン: -
• その他のツール: -
CIサーバー(Masterマシン) ポイント
リポジトリ
• デプロイサーバーに直
デプロイジョブ
•チェックアウト
接チェックアウトしてい
•Windowsバッチの実行 た。
⇒テストのリビジョンと
デプロイのリビジョンが
チェックアウト 異なることが。。。
デプロイサーバー
(Slaveマシン)
• デプロイサーバーには、事前に
ワークスペース
Trac+Subversionをインストール
HelloWorldPlugin が必要
• プラグインのインストールは、
「python setup.py install」コマンド
で実行
Copyright © 2011 NTT DATA CORPORATION 13
- 15. Trac Plugin開発(Seleniumジョブ)
• 流れ:チェックアウト⇒Seleniumコード実行⇒結果出力
• Jenkinsプラグイン:HTML Publisher Plugin(結果表示に利用)
• その他のツール:firefox、Selenium、HTMLTestRunner.py
CIサーバー(Masterマシン)
リポジトリ
ワークスペース Seleniumジョブ
Selenium •チェックアウト
•Selenium実行
チェックアウト •結果保存
Seleniumテスト ポイント
• SeleniumジョブのSeleniumコードの実行は、
デプロイサーバー バッチとPythonのコードで実装しました。
(Slaveマシン) • 下記のプラグインを使うとよりスマートに
実行できます。
• Selenium Plugin
• Selenium AES Plugin
• Seleniumhq Plugin
• SeleniumRC Plugin
• seleniumhtmlreport Plugin
Copyright © 2011 NTT DATA CORPORATION 14
- 17. Trac Plugin開発
ジョブの準備ができたので、実際に開発例を紹介します。
1. コーディング
プラグイン本体のコードを実装
テストコードの実装
2. 単体テスト
コーディング時に実装しなかったテストケースを実装(異常系など)
3. 結合テスト
Seleniumコードを実装
■ 今回実装するコードは、管理画面に「HelloWorldPlugin」のメニューを表示し、リンクをク
リックしたときに画面上に「Hello World」と表示します。
Copyright © 2011 NTT DATA CORPORATION 16
- 18. Trac Plugin開発(コーディング 1/3)
Tracの管理画面を表示するメソッドを実装します。
「helloworld.html」ページに変数「helloworld」に値「Hello World」を格納して渡します。
プラグインのコード(web_ui.py) テストコード(test_web_ui.py)
def render_admin_panel(self, req, cat, page, path_info): def test_render_admin_panel(self):
req.perm.require('TRAC_ADMIN') pass
data = {}
return 'helloworld.html', data
def render_admin_panel(self, req, cat, page, path_info): def test_render_admin_panel(self):
req.perm.require('TRAC_ADMIN') cat = 'helloworldplugin'
data = {'helloworld': "Hello World"} page = 'helloworld'
return 'helloworld.html', data path_info = ''
self.req.perm = PermissionCache(self.env, 'admin')
helloworld_admin = HelloWorldAdminPage(self.env)
templdate, data = helloworld_admin.render_admin_panel( self.req, cat, page, path_info )
assert templdate == 'helloworld.html'
assert data == {'helloworld': ''}
画面上の変更箇所
Copyright © 2011 NTT DATA CORPORATION 17
- 20. Trac Plugin開発(コーディング 3/3)
エラーの発生しているテストコードを修正
テストコード(test_web_ui.py)
def test_render_admin_panel(self): def test_render_admin_panel(self):
cat = 'helloworldplugin' cat = 'helloworldplugin'
・・・ ・・・
assert data == {'helloworld': ''} assert data == {'helloworld': ‘Hello World'}
変数「helloworld」の期待値として「Hello World」を設定します。
ALL OK!!
Copyright © 2011 NTT DATA CORPORATION 19
- 21. Trac Plugin開発(単体テスト 1/2)
異常系操作を行ったときのテストを実装します。
Tracの管理画面は、管理者権限を持つユーザだけアクセス可能。
管理者権限がないユーザでアクセスしたときのテストを実装。
テストコード(test_web_ui.py)
def test_render_admin_panel_error(self):
cat = 'helloworldplugin'
page = 'helloworld'
path_info = ''
self.req.perm = PermissionCache(self.env, ‘wada')
try:
helloworld_admin = HelloWorldAdminPage(self.env)
templdate, data = helloworld_admin.render_admin_panel( self.req, cat, page, self.path_info )
except PermissionError:
pass
else:
self.fail()
期待した権限を持つユーザでないときに発生するエラー
Copyright © 2011 NTT DATA CORPORATION 20
- 23. Trac Plugin開発(結合テスト 1/2)
画面からのオペレーションテストをSeleniumで実装します。
テストは2つ行います。
• Tracの管理画面にアクセスした際に、メニューに「HelloWorldPlugin」と「HelloWorld」が表示されているか。
def test_func_01(self):
sel = self.selenium
num, cap_num = init(1)
sel.open("http://%s:%s@%s/trac/SampleProject/login" % (user, password, server))
sel.open("http://%s/trac/SampleProject/admin" % server) Trac管理画面へアクセス
self.failUnless(sel.is_text_present("HelloWorldPlugin")) メニューの確認
self.failUnless(sel.is_text_present(“HelloWorld"))
cap_num = capture(sel, num, cap_num, test_id, evidence) 画面キャプチャの取得
• リンク「helloworld」をクリックしたとき、画面に「Hello World」と表示されるか。
def test_func_02(self):
sel = self.selenium
num, cap_num = init(2)
sel.open("http://%s:%s@%s/trac/SampleProject/login" % (user, password, server))
sel.open("http://%s/trac/SampleProject/admin" % server)
Trac管理画面へアクセス
sel.click(u"link=HelloWorld") 実装したページへのリンク
self.failUnless(sel.is_text_present("Hello World")) 「Hello World」の表示確認
cap_num = capture(sel, num, cap_num, test_id, evidence) 画面キャプチャの取得
Copyright © 2011 NTT DATA CORPORATION 22
- 25. 最後に
まとめ
• コーディングをする前やコーディングの早い段階でジョブを作成したので、
様々なメリットが得られました!!!(ZFRを実践!)
• リファクタリング時のデグレーションの早期発見
• 実装量、テスト実施量の見える化でモチベーションアップ
• 単体テスト~結合テストまでの自動化で再テスト時の作業の効率化が
できた!!!
• バグ修正時の再テストの効率化
• リリース毎のテスト作業の削減
Copyright © 2011 NTT DATA CORPORATION 24
- 26. 今後取り組みたいこと
• 初期の雛型コードと雛型ジョブを一発で作成したい。
• Jenkinsからバグトラッカーへの連携を設定したい。
• XFDをつけたい。
• Selenium関連のプラグインを効果的に使いたい。
Copyright © 2011 NTT DATA CORPORATION 25
- 27. おまけ
• 現在、Jenkinsに関する本書いています!!
• 今年度中に出版します。
• ぜひ書店で見かけた際には、買ってください!
• こんな内容が書かれる予定です。
1. 継続的インテグレーションについて
継続的インテグレーションについて
2. Jenkinsについて
Jenkinsについて
3. Jenkinsインストールと
インストールと基本設定
Jenkinsインストールと基本設定
4. Jenkinsの基本的な
Jenkinsの基本的な使い方
5. Jenkinsを ってWeb開発をしてみよう
Jenkinsを使ってWeb開発をしてみよう
Web開発
6. 高度な
高度な使い方
Copyright © 2011 NTT DATA CORPORATION 26