paiza開発日誌

IT/Webエンジニア向け総合求人・学習サービス「paiza」(https://paiza.jp ギノ株式会社)の開発者が開発の事、プログラミングネタ、ITエンジニアの転職などについて書いています。

ITエンジニアを目指すなら知っておきたい!システム開発における「テスト工程」とは

f:id:paiza:20190124174941j:plain
Photo by Ruiwen Chua
f:id:paiza:20180910132940p:plainこんにちは。倉内です。

皆さんは「開発系のITエンジニアの業務」と聞くと、システムを開発するためにコードを書くというのがまず浮かぶのではないでしょうか。

それも間違いではないのですが、実務では要件定義・設計・開発・テスト・運用といった工程があります。すべてを担当するかは開発規模や企業にもよりますが「書いたコードをテストする」という作業は必ず発生するため、ITエンジニアにとってテスト工程は避けては通れない道だと言えます。

しかし、実務経験がない方にとっては、「テストってなんとなくは分かるけど、具体的に何をするかはよく分からない…未知の領域…」という感じかもしれませんね。

テストは突き詰めるとかなり奥が深い(それこそ分厚い参考書になるくらい)ですが、今回は「なぜテストをやるのか?」「どのようなテスト方法があるのか?」など、システム開発における「テスト工程」の基本知識を解説してきます。

そもそも「テスト」とは

なぜシステム開発にはテストが必要なのか

一言で言うとテストは「品質の担保」のために実施します。もう少し分かりやすく言うと「できる限りバグをつぶし、仕様どおりに動くことを確かめてからリリース(納品)する」ために実施します。

万が一テストをせずにリリースし、あとで不具合が見つかると利用ユーザーに損失を与えるだけでなく、自社の信頼も失ってしまいます。

特に受託開発では、お客様に開発費用をもらってシステムを作っています。納品後に重大な不具合があった場合は信頼を失うだけでなく、業務への影響度合いによっては損害賠償に発展することもあります。

私の前職はSIerのSEだったため、そういった場面(賠償までいかなくてもお客様へ謝罪に行くなど…)にはたびたび遭遇しました。

また、私たちの社会生活に影響のあるシステムでは、不具合が人の命に関わる場合もあります。テストは実装に比べると地味な作業に感じるかもしれませんが、非常に重要な工程と言えます。

システム開発におけるテストの種類

ウォーターフォール型の開発*1でテストを語るときに欠かせないのが「V字モデル」です。単体テスト、結合テスト、システムテストという単語は聞いたことがあるかもしれません。

この「V字モデル」は、テストを実施する際に上流工程(要件定義~設計)で定めた要件・仕様を満たすかどうか、工程ごとに対応したテストを実施して確認するということを示しています。

詳細設計工程で決めた内容は単体テスト、基本設計工程で決めた内容は結合テスト、要件定義で決めた内容はシステムテストで検証するといった対応になっています。テストの種類によって確認する観点や粒度が異なります。

単体テスト(UT:Unit Test)

テスト工程の中で一番初めにやるのが単体テストです。関数やメソッドといった小さい単位でテストし1つ1つの処理が正しく機能しているかを確認します。

単体テストはテスト対象の単位が小さいため、摘出した不具合の原因特定や修正が比較的容易にできます。そのためできるだけ単体テストで多くバグを摘出する必要があります。テスト工程はあとになるほどテスト対象が大きな単位(複雑に関連した機能など)となり、バグを発見すると原因調査だけでも時間がかかるためです。

単体テスト実施時はまだプログラムが全て完成していないことも多いので、入力データの受け渡しができるように「スタブ」「ドライバ」と呼ばれる一時的な処理プログラムを書くことがあります。

前職のSIerではExcelでマトリックス表を作って人力でテストをすることが多かったのですが、開発ツール上でコードを書いた人がテストするほうが主流になってきています。

結合テスト(CT:Combined Test)

結合テストでは、いくつかのモジュールを組み合わせた際に意図したとおりに動くかを確認します。

もう少し具体的に言うと、ある機能を実現するための部品(=モジュール)を組み合わせて動かしたときに、意図した結果が返ってくるか、データの受け渡しが正しくされるか、データを受け渡すタイミングはずれていないかなどを確認するために実施するテストです。

実は単体テストで見つけられなかった仕様の不備や設計上のミス、単体テストのケース漏れなどの理由から、初めて問題が発覚するのが結合テストという場合がよくあります。そのため、結合テストの工程が遅延したりキツいスケジュールを引いていたりすると、手戻りが発生した場合に取り戻せず、後々まで影響する大きな遅延になってしまう可能性があります。

システムテスト(ST:System Test)

システムテストは総合テストとも言われ、開発環境ではなく、本番同様の環境を準備して実施します。開発したシステムが全体を通して意図したとおりに動作するか、仕様書通りの機能を実現できているか、性能要件を満たしているかなどを確認するために実施します。

本番と同じデータ量やアクセス数で負荷をかけて試験したり、一定期間運用して問題ないかを確認したりといったこともシステムテストでおこないます。

これが開発者側の最後のテストになるので、お客様に引き渡す前にできる限り不具合を取り除き、品質を確保する最後の砦となります。

ここまでくるといよいよリリース(納品)が見えてきます。と言いたいところですが、受託開発の場合、このあとユーザーテスト(受け取り試験、受け入れ試験とも言います)があり、そこで不具合なのか要望なのかのバトルが繰り広げられることが多いので、道のりはまだ長いといった感じです。


アジャイル開発の代表例である「スクラム」では、要件定義・設計・実装・テストというサイクルを短い期間で繰り返します。ウォーターフォール型のようにシステムが完成してからテストというわけではないため、小さい単位でテストを繰り返しますが基本的な考え方は同じです。

2つのテスト技法

テストにはホワイトボックステスト、ブラックボックステストの2種類が存在します。

ホワイトボックステストは主に単体テストで用いられます。書いたプログラムの全処理経路が網羅的に実行されているか確認するテストです。実際の開発現場では、網羅率の目標値をカバレッジという値で算出して、テストが十分かを判断します。

ブラックボックステストは入力値に対して正しい出力値が返ってくる(表示される)かどうかを確認するテストです。ブラックボックステストではシステムの内部がどうなっているかは意識しません。

テスト自動化のススメ

SIerで受託開発の案件をやっていた頃は、昔に比べ短納期かつコストを抑えたプロジェクトが多くなり、テストに割く人員や時間が十分に確保できないという悩みを常に抱えていました。

当時はテストは単価が抑えられる新人・若手を動員し、人海戦術で何千件というテストケースを紙にチェックを入れながら実施していましたが、かなり効率が悪く人的ミスも発生しやすかったなと思います。

今は多くの現場でテスト自動化がおこなわれており、自動化のためのツールもたくさん用意されています。目的によってさまざまではありますが、例えば、WebアプリケーションのUIテストをおこなう「Selenium」、スマホアプリのテストをおこなう「Appium」といった自動化ツールがあります。

実際にテストを実施する手順

paizaが提供しているプログラミングスキルを測るスキルチェックでは、制限時間内に問題を解いて提出し、採点されたスコアでランクづけをおこなっています。

paizaのスキルチェック問題について詳しくはこちら
paizaのスキルチェック

スキルチェックでは、あらかじめテストケースが1~3個用意されており、入力値と出力値が示されています。ただ、このケースを通ったからと言って必ずしも採点で100点を取れるとは限りません。

f:id:paiza:20190125102640j:plain
「動作確認で使うテストケースを選択」で選べる入力例1、入力例2がテスト用入力値

いくつか要因はありますが、用意されているテストケース以外の入力値で結果が誤っている可能性があります。そうなると自分でテストケースを用意して確認する必要が出てきます。

難易度の高い問題ではタイムアウトでテストケースが通らず、計算量を減らす工夫も必要になってくるのですが、今回はそこには触れないことにします。

例として、西暦を入れたら和暦を返す簡単なプログラム問題について考えます。

仕様:
半角数字で渡された数字Yを西暦とし、「元号(漢字2文字)X年」という表記の和暦に変換します。このとき、1926≦Y≦2030、元号には「昭和」・「平成」のどちらかを表示してください。2020以降は「未定」とだけ表示します。

今回は単純化するため日付は考慮せず、1926年~1988年を昭和、1989年~2019年を平成、2020以降を未定とします。また、「元年」表記はせず「1年」でいいです。

最初に書いたコード:
ツッコミどころ満載ですが、このあとの説明のためにいったん目をつむってください。

コードはPythonで書くことにします。Pythonにはコードテストに有用なdoctestunittestといったモジュール群が標準で用意されていますが、そちらについてはまた別途解説したいと思います。(気になる方は公式ドキュメントをご参照ください)

#西暦Yを受け取って、Yの値によって出力を変える
Y = int(input())

print(str(Y) + "年は、", end="")
if(1925 < Y < 1988):
    print("昭和" + str(Y - 1925) + "年")
elif(1988 < Y < 2019):
    print("平成" + str(Y - 1988) + "年")
else:
    print("未定")

とりあえず適当に2ケースくらいテストしておきます。Yの値が1985、2018のときの結果は以下のとおりです。

なんだか合ってそうですね!

1985年は、昭和60年
2018年は、平成30年

なお、こういったちょっとしたプログラムを試してみたいときは、主要24言語に対応しているオンライン実行環境のpaiza.IOを利用すると便利です。

1.まずはテストケースを洗い出そう

ブラックボックステストの技法である「同値分割」と「境界値分析」を用いてテストケースを作ります。

同値分割:
テストといっても、全入力値に対して想定した結果になることを確認する必要はありません。(このくらい単純なケースであれば全部やってみてもいいですが…)テストが必要なパターンを正しく探せればいいということを覚えておきましょう。

今回の仕様では、Yの値を次の3つのグループに分けることができます。

①昭和X年と出力されるべきYの値:1926~1988
②平成X年と出力されるべきYの値:1989~2019
③未定と表示されるべきYの値:2020~2030

よって、入力される可能性のある値は100種類ほどありますが、実はグループ分けすると3つしかないということになります。

同値分割では、この3グループの中から代表値を選んでテストをおこないます。今回は1950、2000、2025あたりを選んでおきましょう。

境界値分析:
境界値分析では、同値分割によって分けられたグループの境界値付近をテストケースとして追加します。今回の例では、1926、1988、1989、2019、2020、2030が境界値となります。

境界値付近は一般的にバグが多いと言われているとおり、特に不等号の間違いや、0を含む・含まないなど誤りやすい箇所が多いです。よって境界値±1の入力値もテストケースとして追加したほうがいい場合もあります。

(参考)例外値:
スキルチェックでは定義された範囲外の値(例外値)が採点時のテストケースに含まれることはありません。しかし、実務では例外値もテストケースに含める必要があります。

例えば、Yは半角数字と書かれていますが、もし文字列が入力されたらどうなるでしょうか?もしくは1000という値が入力されたら?(実際は処理ではなく、入力で制御するのが一般的だと思いますが。)

このような値が入力されたときにシステムが停止してしまうと困ります。例外値が入力されたときにはエラーメッセージを出すなどの処理が必要になってきます。

2.正しい入出力結果を把握するためにテスト条件をまとめよう

テストをしなければならない入力値を洗い出したので、どのような結果が返ってきたらよいのかをまとめましょう。

今回は入力値が1つなのでわざわざテスト条件と期待する結果を一覧にしなくてもよいかもしれませんが、もし入力値が複数(例えば、西暦と日付を渡される)存在する場合は複雑になるためまとめたほうが間違いを防げます。

3.テストのためのコードを書こう

入力値に対して、正しい出力値が分かったので、ようやくテストコードを書きます。

paizaのスキルチェックでは、標準入力から渡された値に対して処理をおこなうことがほとんどなのですが、それでは自由に入力値を設定して結果を確認することができません。

そのためまずはエディタ上で自分が設定した値でコードを実行できるようにします。

#Yにテストしたい値を入れる
Y = []
Y = [1926, 1950, 1988, 1989, 2000, 2019, 2020, 2025, 2030]

for i in range(len(Y)):
    print(str(Y[i]) + "年は、", end="")
    if(1925 < Y[i] < 1988):
        print("昭和" + str(Y[i] - 1925) + "年")
    elif(1988 < Y[i] < 2019):
        print("平成" + str(Y[i] - 1988) + "年")
    else:
        print("未定")
4.テストコードを実行してみよう

これを実行すると……

1926年は、昭和1年
1950年は、昭和25年
1988年は、未定
1989年は、平成1年
2000年は、平成12年
2019年は、未定
2020年は、未定
2025年は、未定
2030年は、未定

あれ?結果が正しくありませんね。例えば、1988年は昭和63年なのに「未定」と表示されています。2019年も同様に「未定」になってしまっています。

これは先ほど実行してみたYの値が1985、2018の2つのテストケースでは気づくことができませんでした。

5.誤った結果が出たらコードを修正しよう

よく見てみると「<」記号で範囲指定している箇所で、境界値が条件外になってしまっているところがあります。

意外にこの値の範囲指定というのは馬鹿にできなくて、まあまあやりがちなミスです。今回は境界値テストをしたおかげで見逃さずに済みました。

範囲指定を修正して再度コードを実行してみます。

#Yにテストしたい値を入れる
Y = []
Y = [1926, 1950, 1988, 1989, 2000, 2019, 2020, 2025, 2030]

for i in range(len(Y)):
    print(str(Y[i]) + "年は、", end="")
    if(1925 < Y[i] <= 1988):
        print("昭和" + str(Y[i] - 1925) + "年")
    elif(1988 < Y[i] <= 2019):
        print("平成" + str(Y[i] - 1988) + "年")
    else:
        print("未定")

出力結果を見てみると…

1926年は、昭和1年
1950年は、昭和25年
1988年は、昭和63年
1989年は、平成1年
2000年は、平成12年
2019年は、平成31年
2020年は、未定
2025年は、未定
2030年は、未定

2.で書き出した入力値Yに対する出力結果の表と一致しました!

これでテスト用に書いたコードを削除して、標準入力からYの値を取得するように処理を戻したら完成です。最初の状態だと、もしかしたらあらかじめ用意されていたテストケースはクリアできたかもしれませんが、提出時に通らないケースがあって減点となっていたでしょう。

今回は非常にシンプルな問題を例に挙げましたが、複雑な問題でもほぼ同じような考え方でテストパターンを考え、テストケースを洗い出すことができます。

(補足)テストにおける目標値

テストを実施することで、不具合はできる限り取り除いてからリリースしますが、完全にバグが0件というシステムはこの世に存在しないと言ってよいでしょう。(運用にほとんど支障がない、軽微なものもバグと呼ぶのであれば)

そうすると「テストってどこまでいったら終わりなんだろう…?」という疑問がわいてきますよね。

そこで実際の現場では、コードの量(ステップ数)に対してテストは何件作成しましょう、バグは何件摘出しましょうという目標値を決めます。この目標値はプロジェクトによって基準が定められており、ひとまずそれをクリアしていれば品質が担保されたと認められます。

しかし、自動生成されたコードに対してもテストをするのか、開発言語や要求仕様の難度は無視してよいのか、拡張性や可読性の考慮の有無はどうするかなど、さまざまな要因でコードの量は変わってきます。それにもかかわらず一律で何件というのはちょっと横暴な気もしますよね。また、作成したテスト件数や摘出したバグ件数が目標値に満たないと、無理やり水増しするような行為も残念ながら存在します。

みなさんが実際にITエンジニアとしてプロジェクトに従事する際は、ただ定められた目標値を満たせばいいではなく、なぜテストをするのかを考えてみてください。

まとめ

システム開発における「テスト工程」について、基本知識の説明と実際のプログラミング問題を例にテストケースを考える手順をご説明しました。

テストの実施方法はシステム開発をおこなう会社やプロジェクトで違いが大きいとは言え、基本的な部分は共通しています。

本文でも紹介したスキルチェックは「解答コードを書いたら即提出!」というやり方もできますが、自分でテストケースを考え、テストを実施するという工程を試すことができます。

ITエンジニアを目指す方にはぜひプログラミング学習を通して、テストもシステム開発の重要な工程の1つであると知っていただけたらと思います。





paizaラーニング」では、未経験者でもブラウザさえあれば、今すぐプログラミングの基礎が動画で学べるレッスンを多数公開しております。

詳しくはこちら

paizaラーニング

そしてpaizaでは、Webサービス開発企業などで求められるコーディング力や、テストケースを想定する力などが問われるプログラミングスキルチェック問題も提供しています。

スキルチェックに挑戦した人は、その結果によってS・A・B・C・D・Eの6段階のランクを取得できます。必要なスキルランクを取得すれば、書類選考なしで企業の求人に応募することも可能です。「自分のプログラミングスキルを客観的に知りたい」「スキルを使って転職したい」という方は、ぜひチャレンジしてみてください。

詳しくはこちら

paizaのスキルチェック

*1:要件定義工程が完了したら設計工程に移る…というように、原則として前工程が完了してから次工程に進む開発手法のこと





※このブログで紹介しているキャンペーンやイベント、およびサイト内の情報については、すべて記事公開時の情報となります。閲覧されたタイミングによっては状況が変わっている場合もございますのでご了承ください。

ITプログラマー・エンジニア転職・就活・学習のpaiza

プログラミング入門講座|paizaラーニング

PHP入門編Ruby入門編Python入門編Java入門編JavaScript入門編C言語入門編C#入門編アルゴリズム入門編AI機械学習入門

エンジニアのためのプログラミング転職サイト|paiza転職

プログラミング スキルチェックエンジニア求人一覧

未経験からエンジニアを目指す人の転職サイト|EN:TRY

プログラミング スキルチェックエンジニア未経験可求人一覧

エンジニアを目指す学生の就活サイト|paiza新卒

プログラミング スキルチェックエンジニア求人一覧

ブラウザを開くだけで エディタ、Webサーバ、DB等の開発環境が整う|PaizaCloud