投稿日 2010年1月25日 月曜日 カテゴリ ソフトウェア開発, テスト 投稿者 syojiComments Off 
あなたの開発チームはバグ管理をどのようにやっていますか?

組込みシステムエンジニアやWebアプリケーションエンジニア、多くのソフトウェア開発に携わる開発者達。 製品開発やシステム開発の現場で「バグ管理」はどのようにおこなっているでしょうか。

  • 「ワープロソフトやスプレッドシート?」
  • 「オリジナルのツール」
  • 「高いライセンス料を払ったシステム?」
  • 「オープンソースで構築」

様々な方法でプロジェクトのバグを管理していると思います。

この記事を見てくださった方達はバグ管理の重要性を知っていて、今のやり方になにかしらの課題があって改善したいとお考えだと思います。

プログラムを開発するとき、複雑で大量にある課題・タスク・バグをきちんと漏れなく管理し、 データベース化しておくことは重要なことです。プロジェクトの成果物やリソース、活動状況をすべて追跡できる仕組みを導入することで、 問題を発見しやすく、製品の品質向上に繋がります。

複雑で大規模化しているソフトウェア開発にとって、バグ管理システムは必須のツールです。

ここで、バグ管理の必要性(メリット)について書き出してみたいと思います。

  • バグデータベースが用意されることで障害についてチーム内の意思疎通がスムーズになる
    • 標準化されたレポートは、自由形式の電子メールや机越しの話よりも正確に内容を伝えることが出来ます
  • データベース化することで、バグの通番管理(追跡と参照)が自動化され、レポートのための分析や報告が提供できる
  • 開発チームは、プロジェクトチーム、マネージャ、顧客、ユーザのそれぞれにとって重要な観点から考え修正を進めることができる。
    • バグ管理システムを使わない場合、開発者やテスターの声が大きい担当者の報告したバグほど早く修正されがちになる
  • バグの発見→レポート→担当者割当→解決について、全てのライフサイクルを通じたバグ管理が出来る。
    • バグがどこかのライフサイクルに潜り込み、早期修正が必要なバグから注意がそれることがない。
  • 開発チームやプロジェクトチーム、テスターの全員が最新の状況を簡単に入手できる。
  • 解決したバグはナレッジとなる。
    • これらのバグ情報は、出荷される製品に紛れ込み、サポート部隊のコストを上げる原因、売上の伸び悩み、使えないシステムという辛らつな評価につながる傾向を見つけることが出来るかも知れない。

参考資料:基本から学ぶテストプロセス管理 – コンピュータシステムのテストを成功させるために -


Webベース バグ管理&バージョン管理システム「Ciklone」
60秒ではじめることが出来る、ソフトウェアエンジニアのためのバグ管理システム

投稿日 2009年8月17日 月曜日 カテゴリ Apache, ソフトウェア開発, テスト 投稿者 syojiComments Off 

Webアプリケーションやクライアントサーバ型のシステム開発の中で性能要件を満たすために負荷試験やロード試験といわれる工程がある。

重要な工程として考えているが、スケジュールの厳しいプロジェクトなどでは後回しにされることがあった。 特に、開発が遅れている場合、要件を満たすための開発が重視されることは理解しているが、負荷試験を実施することは同じくらい大切な工程である。試験で起こることは当然、本番環境でも起こり、あとで痛い目をみないためにも必須の工程である。

負荷試験を設計する上での考え方をまとめてみたいと思う。 以下のサイトが参考になる。

負荷試験とは

構築するシステムがどの程度の負荷に耐えられるかを測定し、システムの信頼性と耐用範囲を明確にする。ウェブアプリケーションの場合、同時アクセスユーザ数をどれだけ処理出来るか、閾値を越えた場合のシステムの振る舞いを検証する試験である。

負荷試験で使われる試験環境は本番環境と同一であることが望ましい。しかし、実際には機器調達が難しいことが多い(例えば、想定している分だけのクライアントマシンを用意する等)。機器が準備できない場合、サーバに負荷を発生させるツール等を使用し、高負荷、過負荷を与え、システムの振舞いについて検証する。

負荷試験の計画(設計)に必要なこと 負荷試験を計画するときに最低限、考えなければいけないことを説明したい。

前提条件

試験を実施するときの試験環境について、サーバの役割、台数、クライアント数、負荷をかける時間等の環境について条件を明確化しておく必要がある。

監視ポイント

例えば、Webアプリケーションの場合、クライアントがアクセスしトップページが表示されるまでの時間。など要件を満たすために必要な監視ポイントを明確にしておく必要がある。サーバサイドではDBに対する大量のI/O(書込、読み出し等)がそれにあたると思われる。

目的と対象範囲

負荷試験でクリアしなければいけない要件、ユーザ数などの試験の目的と対象範囲/ハード情報(各サーバのOS情報/CPU/DISK IO/MEMORY/NETWORK)、過負荷時の測定範囲を明確にする。

性能要件(目標値)

想定されるクライアント数から性能要件を予測し、定義する。レスポンス時間等の試験項目から測定可能な数値を予測する。 例えば年に1度のみ過負荷が発生するといった事象に合わせてシステムを組んだ場合、性能要件は十分であるが、コスト面で満足するものにはならない場合がある。そのため、要件にあった目標値を設定することは重要である。

想定シナリオ

構築するシステムの利用シーンを考えたシナリオを作成する。試験実施はそのシナリオに沿って行われるべきである。 例えば、メールクライアントの場合、社員が出社する時間(09:00頃)が大量のアクセスが発生する、など。その利用シーンをシナリオに組み込む。

実施方法

市販のツールを利用する、自作ツールを利用する、など目標値を達成するためには過負荷状態を作らなければいけない。疑似的に過負荷状態を作り出す必要がある。Webアプリケーションに限定されるが無料ですばらしいツールが多く提供されている。

試験結果

負荷試験計画時の「目的と対象範囲」を達成したかどうか、 実測値が予測値より悪い場合や、目標値ギリギリの場合、チューニングを実施することになる。 問題点の原因については、計測データなどを使って

  • トランザクション数/クライアント数が増加しているとき、スループットの増加傾向が変化した時点
  • レスポンスタイムが急速に遅くなった点

分析するポイントとして、システムの測定値が急激に変化したとき、関連するモジュールがボトルネックと考えられる。 チューニングについては、そのようなボトルネックと予測されるモジュールから優先的に検証する必要がある。

以上のような点について、負荷試験の計画フェーズで考えておけば良いのではないかと考える。 負荷試験が実施されるのはシステムが構築され、結合試験も終わった以降になる。一番忙しいフェーズであるが 負荷試験の重要性を説明し、しっかりと計画をして実施していきたいと思う。

投稿日 2009年8月3日 月曜日 カテゴリ ソフトウェア開発, テスト, プロジェクト管理 投稿者 syojiComments Off 

ソフトウェア開発プロジェクトでは、単体/結合/総合/受入試験と製品開発の工程により観点の異なる試験フェーズが存在している。

試験の目的の1つは、

「ユーザが利用しているとき、故障が発生しないよう、事前にあらゆる種類の故障を見つけておくこと」

である。 しかし、現実的に全てのバグを発見することは難しい。

そこで、「良い試験項目」を作成し、限られた時間内に多くのバグを見つけることを行う必要がある。 今回は試験工程(単体、結合、総合)で試験内容の粒度・観点について説明すると

それだけで相当な文書量になるため、「良い試験項目とは?」として押さえておかなければいけない点を説明したい。

「良い試験項目」とは

  • 試験実施の方法が説明してあること
  • 期待値(捜査の結果)が明示してあること
  • 「試験日、担当、結果」が記録されること
  • バグを発見できる可能性が高い内容であること
  • 重複がないこと
  • 単純すぎず、複雑すぎないこと

試験項目を作成するときには、工程や手法によって異なるが「ソフトウェアテスト – Wikipedia」で説明されている点と同じように、

「バグはどうやって発生するのか?」

を考えながら試験項目を作成するとうまくいく場合が多い。

また、バグデータベース(過去の失敗事例、バグトラッキングシステム/BTS)があれば、過去の事例からバグを分析してみると参考になることが多い。

開発の現場でよく発生する例として

本来なら前工程で検出されなければいけないバグが、後工程でみつかることがある。

「なぜ、見つけなければいけない工程で漏れてしまい、後工程で見つかったのか?」

をプロジェクトメンバーが考えることが品質の向上、次のプロジェクトの分析材料になっていく。

過去のプロジェクトの失敗事例や「なぜ、バグが漏れたのか?」をチームで考え、

共有していくことが品質管理の第一歩だと考えている。

zeera document search

zeera document search で仕事の効率アップ!

「バリバリ働きマン」「めんどくさがりさん」 zeera document search で仕事の効率Up!

投稿日 2009年7月30日 木曜日 カテゴリ Python, テスト 投稿者 sugimotoコメント(0) » 

sugimoto です。

Pythonの単体テストのツール unittest を使ってみました。

1. まずはマニュアル通りに。。

Python – unittestのマニュアルから、TestSequenceFunctions を実行します。

# python testsequecefunctions.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.002s

OK

普通に成功しましたね。

2. TestSuite を実行する

今度は複数のTestCaseからなる、TestSuiteを実行してみます。

TestCaseは同じものを使ったので、命名のセンスが悪くてすいません。。

2つのTestCaseをまとめて実行するTestSuite

[testsuite.py]

import unittest
import testsequecefunctions as TestSequenceFunctions
import testsequecefunctions2 as TestSequenceFunctions2

suite1 = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions.TestSequenceFunctions)
suite2 = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions2.TestSequenceFunctions2)
suite = unittest.TestSuite([suite1, suite2])
print suite.countTestCases()

runner = unittest.TextTestRunner()
runner.run(suite)

実行すると

# python testsuite.py
6
......
----------------------------------------------------------------------
Ran 6 tests in 0.002s

OK

6個のテストがすべてパスしました。

3. trac plugin をテストしてみる

trac のestimationtools pluginをテストしてみます。すでにテストコードも提供されているので、今回は実行するだけです。

# unzip estimationtoolsplugin-r6309.zip
# cd estimationtoolsplugin/trunk/estimationtools/tests
# ll
total 24
-rw-r--r-- 1 root root 9264 Jul 29 11:18 burndownchart.py
-rw-r--r-- 1 root root 2696 Jul 30 10:46 hoursremaining.py
-rw-r--r-- 1 root root 2283 Jan 26  2009 workloadchart.py

そのまま実行できるようにスクリプトの最後に以下のコードを追加しておきます。

if __name__ == "__main__":
    unittest.main()

そして実行

# python burndownchart.py
Traceback (most recent call last):
  File "burndownchart.py", line 3, in ?
    from estimationtools.burndownchart import BurndownChart
ImportError: No module named estimationtools.burndownchart

エラーになりました。。

estimationtools.burndownchart がないということですね。。

plugin 本体のディレクトリにパスを通しておきます。

# export PYTHONPATH=/root/plugins/estimationtoolsplugin/trunk/

再度実行します。

# python burndownchart.py
...FFF......
======================================================================
FAIL: test_calculate_timetable_with_closed_and_reopened_ticket (__main__.BurndownChartTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "burndownchart.py", line 140, in test_calculate_timetable_with_closed_and_reopened_ticket
    self.assertEqual(timetable, {day1: Decimal(10), day2: Decimal(0), day3: Decimal(0), day4: Decimal(5)})
AssertionError: {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("0"), datetime.date(2009, 8, 1): Decimal("0"), datetime.date(2009, 8, 2): Decimal("5")} != {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("10"), datetime.date(2009, 8, 1): Decimal("0"), datetime.date(2009, 8, 2): Decimal("5")}

======================================================================
FAIL: test_calculate_timetable_with_closed_ticket (__main__.BurndownChartTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "burndownchart.py", line 113, in test_calculate_timetable_with_closed_ticket
    self.assertEqual(timetable, {day1: Decimal(10), day2: Decimal(5), day3: Decimal(0)})
AssertionError: {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("0"), datetime.date(2009, 8, 1): Decimal("0")} != {datetime.date(2009, 7, 31): Decimal("5"), datetime.date(2009, 7, 30): Decimal("10"), datetime.date(2009, 8, 1): Decimal("0")}

======================================================================
FAIL: test_calculate_timetable_with_closed_ticket2 (__main__.BurndownChartTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "burndownchart.py", line 126, in test_calculate_timetable_with_closed_ticket2
    self.assertEqual(timetable, {day1: Decimal(10), day2: Decimal(0), day3: Decimal(0)})
AssertionError: {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("0"), datetime.date(2009, 8, 1): Decimal("0")} != {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("10"), datetime.date(2009, 8, 1): Decimal("0")}

----------------------------------------------------------------------
Ran 12 tests in 0.478s

FAILED (failures=3)
#

今度はうまくいった。。と思ったら、なぜかテストが失敗しましたね。。

4. estimationtools plugin のtest suite を実行する

estimationtools plugin には3つのテストがあるので、すべて実行するためのスクリプトを作ります。

[testsuite.py]

import unittest
import burndownchart as burndownchart
import hoursremaining as hoursremaining
import workloadchart as workloadchart

runner = unittest.TextTestRunner()
suite = unittest.TestLoader().loadTestsFromTestCase(burndownchart.BurndownChartTestCase)
runner.run(suite)

suite = unittest.TestLoader().loadTestsFromTestCase(hoursremaining.HoursRemainingTestCase)
runner.run(suite)

suite = unittest.TestLoader().loadTestsFromTestCase(workloadchart.WorkloadChartTestCase)
runner.run(suite)

3つのテストをロードして、実行するだけです。簡単です。

実行してみます。

# python testsuite.py
...FFF......
======================================================================
FAIL: test_calculate_timetable_with_closed_and_reopened_ticket (burndownchart.BurndownChartTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/root/plugins/estimationtoolsplugin/trunk/estimationtools/tests/burndownchart.py", line 140, in test_calculate_timetable_with_closed_and_reopened_ticket
    self.assertEqual(timetable, {day1: Decimal(10), day2: Decimal(0), day3: Decimal(0), day4: Decimal(5)})
AssertionError: {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("0"), datetime.date(2009, 8, 1): Decimal("0"), datetime.date(2009, 8, 2): Decimal("5")} != {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("10"), datetime.date(2009, 8, 1): Decimal("0"), datetime.date(2009, 8, 2): Decimal("5")}

======================================================================
FAIL: test_calculate_timetable_with_closed_ticket (burndownchart.BurndownChartTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/root/plugins/estimationtoolsplugin/trunk/estimationtools/tests/burndownchart.py", line 113, in test_calculate_timetable_with_closed_ticket
    self.assertEqual(timetable, {day1: Decimal(10), day2: Decimal(5), day3: Decimal(0)})
AssertionError: {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("0"), datetime.date(2009, 8, 1): Decimal("0")} != {datetime.date(2009, 7, 31): Decimal("5"), datetime.date(2009, 7, 30): Decimal("10"), datetime.date(2009, 8, 1): Decimal("0")}

======================================================================
FAIL: test_calculate_timetable_with_closed_ticket2 (burndownchart.BurndownChartTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/root/plugins/estimationtoolsplugin/trunk/estimationtools/tests/burndownchart.py", line 126, in test_calculate_timetable_with_closed_ticket2
    self.assertEqual(timetable, {day1: Decimal(10), day2: Decimal(0), day3: Decimal(0)})
AssertionError: {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("0"), datetime.date(2009, 8, 1): Decimal("0")} != {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("10"), datetime.date(2009, 8, 1): Decimal("0")}

----------------------------------------------------------------------
Ran 12 tests in 0.619s

FAILED (failures=3)
.....
----------------------------------------------------------------------
Ran 5 tests in 0.692s

OK
..
----------------------------------------------------------------------
Ran 2 tests in 0.126s

OK

1つめのテストケースはやっぱり失敗しますが、残りのテストケースはすべて成功しました。

今回は既存のplugin に添付されているテストケースを使いましたが、自分がpluginを作ったときもテストケースを書きたいと思います。

参考