新入社員ブログ 斎藤06[PHPUnitデータプロバイダ]

25年度入社の斎藤です。

 以前、斎藤04[PHPUnitについて]のブログでは、以下のようにテスト対象のクラスメソッドに対して、1つのデータだけを使って、メソッドの動作を検証しました。

※addメソッドに対して、引数(2,3)の場合のみ検証

しかし、上記の結果で得られる検証結果は引数が(2,3)の場合は正常に機能するということしか保証できません。
実際のテストでは様々な入力を用いて多角的に検証していく必要があります。PHPUnitにはそのための便利な機能として、データプロバイダ(DataProvider)があります。今回は、そのデータプロバイダの使い方について簡単に説明していきます。

データプロバイダの作成・紐づけ

 今回は斎藤04[PHPUnitについて]のブログですでに作成したテストコード(Sample_Test.php)を流用し、これにコードを追記することでデータプロバイダを利用することにします。
データプロバイダによるテストの対象はaddメソッドとします。

Sample_Test.php(以前のブログで作成済み)



1.データプロバイダの参照を追加
まず、データプロバイダがテストコード内で利用できるように以下の参照をテストコードに追加します。

2.テストメソッドを引数をとるカタチに修正
前回はテストメソッド(test_add)内で、テスト対象のメソッドであるaddメソッドを呼び出し、その引数にデータ(2,3)を直接記述しました。

以前のテストメソッド(test_add)

今回は、このテストメソッドを以下のように修正することで、任意の入力でaddメソッドを検証できるようにします。

修正1: addメソッドの引数を変数に変更する
add(2,3) → add($var1,$var2)

修正2: アサーションメソッドの期待出力値を変数に変更する
assertEquals(5,$result) → assertEquals($expected,$result)

修正3: テストメソッドがこれらの変数を引数として受け取れるようにする
test_add() → test_add($var1,$var2,$expected)

これらの修正を加えるとテストメソッド(test_add)は以下のようになります

3.データプロバイダを作成する
データプロバイダはテストメソッドの引数に合わせるように作成していきます。データプロバイダはメソッドとして作成することができ、テストメソッドの直下に記述します。以下の例(SampleDataProvider)にあるように、データの組み合わせによってパターン名を付けることをができます。このパターン名はテスト実行時に表示されるので、どのパターンの認証が成功し、失敗したのか一目で分かります。

データプロバイダの例(SampleDataProvider)


今回のテストメソッド(test_add)は

第1引数($var1): 任意の整数
第2引数($var2): 任意の整数
第3引数($expected): $var1と$var2の合計

よって、データプロバイダに用いるデータの組み合わせは以下のようなものが考えられます。
[任意の整数,任意の整数,2つの整数の合計値]
= [1,1,2][2,2,4][0,0,0][-1,-2,-3]…..etc

今回はデータプロバイダを以下のように定義します。
メソッド名: additionDataProvider

4.テストメソッドとデータプロバイダを紐づける
テストメソッド(test_add)の1行上にピッタリと乗せるように、以下の記述を追加します。これによってテストメソッドとデータプロバイダが紐づけられます。

以上で、データプロバイダの追加は完了です。テストコード全体は以下のようになります。

以下のテストコマンドを実行します。

これで、データプロバイダで作成した3つのパターンのaddメソッドの検証と1つのパターンのsubメソッドの検証が行われ、全ての検証が正常に終了したことが分かります。

最後に

 データプロバイダを使えば、テストメソッドを検証のパターンごとに何個も記述せずに済むため、テストコードがかなりスッキリしてとても便利であると感じました。特に境界値テストなど、似たようなテストを複数実行したい場合に重宝すると思います。

以上で今回のお話をおわります。
ありがとうございました。

新入社員ブログ 斎藤04[PHPUnitについて]

25年度入社の斎藤です。

 クラスやメソッド単位での動作を保証するために行う、単体テストというものがあります。今回は、テストコードを記述することで単体テストを自動化する機能をもつPHPUnitについて、Laravelのwebアプリケーションへの導入方法と使い方を簡単に説明しようと思います。

PHPUnitの導入方法

 Laravelを導入している場合、phpunitは標準でインストールされているため、特にインストール操作は必要ありません。

テストコードの作成

 PHPUnitでの単体テストは、テスト対象となるクラスとテストコードを1対1の関係で作成していきます。

Laravelプロジェクトフォルダ内で以下のコマンドを打つことで tests/units 配下に単体テストファイル(Sample_Test)を作成できます。

作成できたテストファイル tests/unit/Sample_Test.php にて以下のコード変更を行います。

※テストフォルダには、単体テストファイル用フォルダのtests/unit、結合テスト用のフォルダのtests/featureが存在します。unitフォルダ内に作成されるテストファイルは、厳密な単体テスト用のファイルとして作成されるため、デフォルトではLaravelが提供する外部依存機能機能(トランザクション、ファクトリー、シーダー、ファサード認証など)が使えません。しかし実用的には単体テストにおいても、これらのLaravelの機能を含めた単体テストを行うことがあるので、上記のコードの変更を行いました。

結果、以下のようなテストコード(Sample_Test.php)のひな型が作成できます。

Sample_Test.php

次にテスト対象として、足し算、引き算の機能を持つクラス(SampleClass.php)を作成します。

SampleClass.php

これで、テスト対象となるクラス(SampleClass.php)とテストコード(Sample_Test.php)のひな型を1対1で用意できました。最後に、テストコードを編集して、テスト対象のクラスをテストできるようにします。

テストコードファイル内で追記する主な内容は

1.テストクラス内に、テスト対象のクラスのオブジェクトを定義する
 テストクラスの中で使用するテスト対象のオブジェクトを、プロパティ(変数)として宣言します。


2.setUp関数を定義する
各テストメソッドが実行される前に毎回自動で呼ばれる特別なメソッドです。
ここでテスト対象のオブジェクトを作成します。
こうすることで、テストメソッドごとに毎回新しい状態のオブジェクトを使えるようになり、テスト同士が影響し合うのを防げます。
parent::setUp()は初期化処理を継承するために必須の記述です。


3.テスト対象のメソッドごとにテストメソッドを作成する(テストメソッド名は test….)
基本的に、テスト対象のメソッド1つに対して、テストメソッドも1つ作成します。
テストメソッドごとに、テスト対象の各メソッドをテストしていくイメージです。
実際のテスト内容をここに記述します。
テストメソッド名はテスト対象のメソッド名と対応させると分かりやすいです。


4.テストメソッド内で、テスト対象クラスのオブジェクトからメソッドを呼び出し実行する

setUpメソッドで作成したテスト対象のオブジェクトを使って、実際にテストしたいメソッドを呼び出します。


5.メソッドを呼び出した後、期待する結果を検証していく(assertion)

期待する結果と実際の結果が一致しているかを検証する手段として、assertion(アサーション)が用意されています。
具体例として
・予測値と実際の結果を比較するメソッド : assertEquals()
・trueかどうかを検証するメソッド : assertTrue()
・配列の数を検証するメソッド : assertCount()
などがあります。
これをテストメソッド内で利用していきます。

これら1~5の内容をテストコード(Sample_Test.php)に追加すると以下のようになります。

あとはテストコードを実行するだけでテストを行えます。
テスト実行コマンドは以下の通りです。

作成した全てのテストファイルを実行する場合

特定のテストファイルを実行する場合

テストコードを実行すると以下のような結果が得られます。
今回の二つのメソッド(add、sub)は想定通りに機能していることが確認できました。

最後に

 PHPUnitを学んで率直に感じたことは、テストコードを記述していくことはかなり労力がかかる作業であるということです。テスト対象のコードとテストコードを対にして記述していく必要があるため、単純計算で2倍程度のコードを記述することになります。小規模なシステムや修正があまり発生しないコードでは、この労力は割に合わないかもしれません。しかし、システムが大規模になり、複数人での開発や頻繁な変更が発生する環境では、自動テストによって迅速に品質を保証し続けられるメリットは大きいものなのだろうと思いました。

以上で今回の話をおわります。
ありがとうございました。

テストの基本の”き”をおさえよう!

’23年度入社の紙屋です!
本年度は単体テストに対して理解を深め、成果物のクオリティを担保するという点を目標の一つとして業務に取り組んでまいりました。
リリース前にテストを行い、早期に不具合を発見することもできましたが、テスト内容の不十分さや検証環境へリリース後、お客様からのご指摘で不具合を発見するなどの反省点もありました。
テストを行うための心構えとして備忘録的にまとめようと思います!

テストの目的と重要性

  • バグの早期発見と修正が可能
  • プログラマーの心理的安全性を保つ
  • 機能改修時の予期せぬエラーを防ぐ
  • コードの挙動理解を助ける

テストの考え方

  • FeatureとUnitに分けて管理することが多い
    * Feature(機能)テスト:
    ユーザー目線のテストです。
    より大きい範囲で行い、アプリケーションに求められる機能を確認します。
    * Unit(単体)テスト:
    プログラマ目線のテストです。
    より小さい範囲で行い、各パーツごとにエラーがないかを確認します。
  • ブラックボックステスト、ホワイトボックステストの目的を意識する
    * ブラックボックステスト:
    システムの外部から機能や仕様を検証します。
    システムが仕様通りに動作するか、画面レイアウトや使いやすさを評価することに重点を置きます。
    * ホワイトボックステスト:
    内部のコード構造や処理フローを検証します。
    内部ロジックのの正確性を評価します。

テストの作成

テストの作成から実行方法までLaravelを使用した方法でまとめようと思います。

  • テスト作成のコマンド:

    上記コマンドはFeatureテストとして作成されます。
    もしもUnitテストとして作る際は、オプションを付けましょう。


    * ファイル名は通常 ‘XxxxTest.php’ の形式を指定します。

テストケース名には必ず「test」と入れ、「test***」とテスト名と条件なども記載します。

テストコードの構造

テストコードは以下のような形をとります。

setUp や tearDown はテストケースの事前・事後処理を行います。
* setUp:事前処理(変数の初期化やデータの準備など)
* tearDown:事後処理(不要なデータの削除など)
* setUpやtearDownを書く際は、メソッドの戻りと指定 ‘: void’ も忘れずに書くことが必要です。

アサーションについて

プログラミングのデバッグやテストのために用いられる方法の1つです。
以下のような働きをします。

  • テスト結果を即座に確認できる
  • テストが意図した通りに動作したかを検証できる
  • テスト条件が妥当なデータかを判断できる
  • テストが失敗した要因を特定しやすい

アサーションメソッドは主に以下のようなものがあります。

  • assertTrue:実測値がtrueであることを期待
  • assertFalse:実測値がfalseであることを期待
  • assertEquals:実測値と予測値が一致することを期待
  • assertSame:実測値と予測値が型も含めて一致することを期待
  • assertEmpty:中身が空であることを期待
  • assertNotEmpty:中身が空でないことを期待
  • assetStatus:アクセス結果のステータスコードを確認
  • assertRedirest:アクセス後、どこにリダイレクトされるかを確認
  • assertSee:レスポンス内に特定の文字列が存在することを確認

テストの実行方法

  • 全てのテストを実行する場合
  • フォルダを指定してテストを実行する場合(例:フォルダ名tests/Feature)
  • ファイルを指定してテストを実行する場合(例:ファイル名ExampleTest.php)
  • メソッド名を指定してテストを実行する場合(例:メソッド名testExample)

テストコード作成のポイント

  1. テストメソッドは簡潔に保つ
    呼ばれるアサーションを条件分岐してしまうと、一貫したテスト結果が得られなくなる可能性があります。結果が数パターンある場合は、愚直にそのパターン数分テストを準備する必要があります。
  2. 必ず通るテストを書く(時間依存や確率的要素を避ける)
  3. ダミーデータは実際の内容に近い内容にする
    データはより正確な方が本番環境に近い挙動のテストを行うことができます。
  4. テスト対象となるロジックはシンプルにする
    複雑な条件になりそうな場合はメソッド化して対応します。そのほうがテストケースも少なくて済むことがあります。
    ロジックはネスト構造を複数持たないよう心掛け、アーリーリターンを設けるなど対応します。
  5. 3つのAを意識する
    〇 Arrange(準備):テストを行うにあたっての必要な準備段階のこと
    〇 Act(実行):準備したデータを元にアクションを起こすこと
    〇 Assert(検証):アクション後に期待する結果になっているか検証すること
    上記3つのAを意識してテストを行います。

以上がテストについての基本になります。
単体テストを適切に実施することで、コードの品質向上とメンテナンス性の改善につながります。
なかなか時間が十分にとれず、また、多数存在する条件の洗い出しもできないとシステムの品質を担保することは難しいです。
先日参加したPHPカンファレンスでもテストの重要性に触れ、テストを書く習慣をつけ、継続して改善、向上していくように意識するようになりました。
開発に時間がかかりがちですが、テストの時間も十分に設け、自分へのフィードバックも兼ねて今後も取り組んでいきたいと思います。
日々の取り組みを重ね、また理解が進んだ段階でアウトプットできればと思います!

新入社員ブログ 松井(第5回)

こんにちは。松井です。もうすぐ2月になりまだまだ寒い時期が続きますね。

今回はOJTについて紹介します!内部研修が終わって、8月からOJTに参加しています。OJTということで、案件に参加していますが、私の場合は基本設計から参加しました。難しい作業を割り振られることはありませんが、とにかく仕事に慣れることに苦労しました。1月末までどんなことをやってきたか、簡単になりますが紹介します!

基本設計・詳細設計

お客様との打ち合わせや社内会議を聞いてメモを取ったり、画面設計書を見ていました。また、先輩社員がテーブル定義の物理カラム名の名前をつけていました。画面設計書やテーブル定義について「おかしい!」と思ったところは迷わず先輩社員に質問していきました。例を2つ挙げると画面設計書に書いてあることがテーブル定義に書かれていないといった資料での漏れとテーブル定義には必須扱いになっているにもかかわらず画面設計書では必須ではないといった資料間による矛盾です。冷静に資料を見比べることで漏れや矛盾が無いかチェックをしていましたので、該当する部分が資料内にあるか探すのが大変でした。しかし、設計段階で漏れや矛盾を減らしたということにおいてはやりがいを感じられました!

API仕様書・詳細設計書作成

簡単な処理のAPI仕様書・詳細設計書を作成しました。最初はやり方が分からず簡単そうな画面を先輩社員に教えてもらいながら一通り作成しました。最初は簡単な仕様の詳細設計書を書きましたが、やり方が分からず先輩社員が作成した詳細設計書を参考に書くようにしました。ある程度詳細設計書を書いたら「内容は違っても他の詳細設計書にも同じことを書ける」ということを意識するようにしました。その際に自分たちが作った設計書をもとに実装されるので、「仕様が違う」ということが無いように気を付けるようにしました。

API実装・テスト

今は作成したAPI仕様書や詳細設計書を元にAPIを実装しつつ、テストして想定した挙動になっているか確認しています。研修で学んだLaravelで実装しておりますが、実際に仕事として使うのは始めてでプログラムの書き方に戸惑うことがあります。しかし公式ドキュメントやQiita等で使い方を調べて出来る限り自力でプログラムを組めるように努力しています!

今回はここまでです。次回はフォローアップ研修について紹介します。最後まで読んで頂きありがとうございます!

PHPカンファレンス福岡2018

先週末に開催されたPHPカンファレンス福岡に参加したのでその感想を簡単に。
https://phpcon.fukuoka.jp/2018/

PHPカンファレンス福岡は今年で4回目。
もともと東京で行われたPHPカンファレンスに参加できなかった人が「PHPカンファレンス福岡」とつぶやいたことから有志が集い福岡で開催が決定したというのが興味深いですね。
弊社はブロンズスポンサーとして出資しています。

朝から夕方まで開催されていて、主に初心者向けのセッションが多くありました。
また、MySQLやコンテナ技術などPHPに関係しないセッションも多く、Webアプリ全般技術勉強会みたいな感じでした。

「skaffold を使って Kubernetes してみた」

Kubernetes(くーべねてぃす)のセッションです。
オープンソースの「コンテナオーケストレーションシステム」で、Dockerが正式採用したのを皮切りに、AWS、MS Azureも次々に正式対応をしたということが説明されており、事実上の標準になったのではないか、ということでした。
今後コンテナを使って開発/勉強を行うときには合わせて使ったほうがよさそうです。

「0から始めるLaravel相談会」

匠の技を倣うならドキュメントを読め!
特にLaravelのドキュメントは良く書かれており、英文も単語を抜き出して読み進めればわかるはずだ!
みたいなセッションでした。
確かにオリジナルドキュメントは大事ですね。

「Testing Live!!!」

テストをやる人がどういった視点でテストをするのか?5分間の解説付きで実演していました。
アカウントやパスワードのテキスト入力枠にhtmlのタグ付き長文を入力する、表記ゆれが気になる~、などあるあるだけどついついおろそかにしがちなことをテスターの心情を交えながら説明されてて、面白かったです。

各セッションのスライドの多くは「Speaker Deck」にアップされています。
https://togetter.com/li/1237797

セッション以外にもスポンサー企業ブースが併設されていていました。
ノベリティ有り、コーヒーサービスありでゆっくり見て回れるようになっていました。

参加者全員に配られたバッグや先着で配られたTシャツもよかったです。

[PHP]Seleniumを使ってみよう(2)

福岡拠点の野田です。
前回「Seleniumを使ってみよう(1)」では、Selenium サーバーを立ち上げるところまで実施しました。
https://blog-s.xchange.jp/?p=418

今回はその続きです。
弊社では、PHPを使うことが多いので、その例を紹介します。
PHPがローカル環境にない方は、さくっとインストールしてください(環境変数にパスを通すのも忘れずお願いします)。
http://www.php.net/downloads.php

composerが入っていなかったら、インストールします。
https://getcomposer.org/doc/00-intro.md#installation-windows

任意のフォルダにcomposer.jsonを配置します。

facebook/webdriverは、curl関数を使うため、php_curlのエクステンションを有効にします。ほかにスクリーンショットの編集等でgdライブラリを使う場合がありますので、php_gd2のエクステンションを有効にします。

ちなみに php.ini のある場所は、php -i で表示することができます。

cmd でDOSのターミナルを開いてcomposer.jsonを配置したフォルダでcomposer update を実行してください。必要なライブラリをインストールします。これでSeleniumを使ってテストを実行する準備が整いました。

サンプルコードを以下にアップしています。

https://github.com/nodat/php-selenium-tools

processor.php と scenario.yaml を composer.json のフォルダに配置してください。

以下のようなバッチを作成して実行することで動きます。

まだまだ粗削りですが、scenario.yaml を作りこんでいくことで E2E のテストを実現することができます(適宜、バージョンアップしていきます)。
細かい処理については、ソースコードを解析して見てください。

[PHP]Seleniumを使ってみよう(1)

福岡拠点の野田です。今回は、Seleniumを使った自動テストをやろうということでSeleniumの環境構築まで紹介しようと思います。

SeleniumはJavaで動かすことができます。Javaがインストールされていない環境では、JRE(ランタイム、単体実行向け)もしくはJDK(開発者向け)をインストールする必要があります。

Java SE Runtime Environment 8 Downloads
http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html

各環境にあったファイルをダウンロードしてインストールしてください。

続いてSeleniumサーバーをダウンロードします。

https://www.seleniumhq.org/download/

Seleniumはサーバーとブラウザを操作するWEBドライバーの組み合わせ動きます。

まずは、Selenium Standalone Serverをダウンロードします。ダウンロードしたファイルを任意のフォルダに配置します。

あとは以下のドライバーをダウンロードして、上記と同じフォルダに放り込みます。

The Internet Explorer Driver Server (IEを操作。IEDriverServer.exe)
※SeleniumのサイトよりDL

Mozilla GeckoDriver (Firefox を操作。geckodriver.exe)
https://github.com/mozilla/geckodriver/releases

Google Chrome Driver (Chromeを操作。chromedriver.exe)
https://sites.google.com/a/chromium.org/chromedriver/

起動するには、仮に server.bat として以下のような内容でバッチを作成します。

※上記は、IE + Chrome を指定する例

server.bat をダブルクリックするとSeleniumサーバーを起動することができます。

続き:https://blog-s.xchange.jp/?p=424