質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

PHPUnit

PHPUnitは、PHP向けのユニット・テスト向けフレームワークで、手動では手間のかかるテスト作業を自動化し、繰り返し実行することが可能です。

Q&A

解決済

1回答

6440閲覧

PhpUnitで、親クラスのメソッドを差し替えたい

th1209

総合スコア40

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

PHPUnit

PHPUnitは、PHP向けのユニット・テスト向けフレームワークで、手動では手間のかかるテスト作業を自動化し、繰り返し実行することが可能です。

1グッド

0クリップ

投稿2016/01/29 08:04

はじめまして。th1209と申します。
テラテイルではじめて質問させていただきます。

現在Php/PhpUnitを使った開発に携わっており、
テストが書けないケースに直面し、困っております。

色々調べてはみたのですが、どうも解決策が見つかりませんでした。
(PhpUnitでは実現不可能かも><)
テストに詳しい方、どなたかご教授いただけませんか?

困っている問題、聞きたいこと、サンプルコードは以下になります。
どうか宜しくお願いしますm(_ _)m

問題点

あるサブクラスのテストコードを書いています。
サブクラスのメソッド内で、親クラスのメソッドを呼んでいます。
この親メソッドが問題で、内部で他APIとの通信を行っています。
そのため、テストケースを記載することが困難な状態です...。

教えて欲しいこと

以下のようなサンプルコードがあった際、テストの時だけ親クラスのメソッドを差し替える方法。
PhpUnitを使って開発しているので、PhpUnitでの解決策を教えて欲しいです。
※「PHPUnit以外に、こんなテストフレームワークを使えば実現できる」とか、
「そもそもテストしやすいよう、XXXな設計にすべき」という回答も大歓迎です!

php

1<?php 2class SampleSubClass extends SampleClass{} 3 4 public function sampleMethod() 5 { 6 7 //この親メソッドに悩まされている... 8 //内部で、がっつり他APIとの通信処理が行われている 9 $ret = parent::sampleMethod(); 10 11 //戻り値に応じて処理を切り替える。 12 //サブクラスのテストで見たいのは、あくまでここだけ。 13 if ($ret) { 14 //do something 15 }else{ 16 //do something 17 } 18 } 19} 20?>
ikuwow👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

どういった通信をしているのかわからないのですが、そこの通信部分のテストが的確であれば
mockを使ってその通信を返してあげれば良いのではないでしょうか。

単純に内部APIを呼んでいるmethodをmock化してsetUpに記述してあげるようなことをすればテストは書き易いかと思います。

php

1$this->sample = $this->getMockBuilder("Sample")->setMethods(['hoge'])->getMock(); 2$this->sample->method("hoge")->willReturn("foo");

みたいな感じです。
※記憶が正しければですが。。。書き方はこんな感じです。

上記のプログラムで動くかは別として、(自分で書いておいてなんですが)mockで対応することはできるかと思います。

投稿2016/01/29 09:52

編集2016/01/29 10:31
deadcode

総合スコア216

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

th1209

2016/01/30 07:12 編集

deadcodeさん ご回答ありがとうございます。 おっしゃる通り、 通信処理を行っているメソッドをモックとして切り出し、 テストしたいクラスに渡すことができれば、 上手くテストできるのかなと思います。 ただ、対象メソッドのモックを作っても、 テストしたいクラスに渡せなくて、困っています...。 (メソッドの内部で親クラスのメソッドを直接呼んでしまっているため) ちょうど以下のようなサンプルコードの状態なのですが、伝わるでしょうか...? ``` php <?php //親クラス class SampleClass{ HttpConnectionMethod(){ //通信系のAPIを呼ぶ処理 } } //テストしたいクラス class SampleSubClass extends SampleClass{ //オーバーライド HttpConnectionMethod(){ //親のメソッドを内部で呼んじゃってる。 //なので、モックを渡せない... $ret = parent::HttpConnectionMethod(); //戻り値に応じた事後処理 if($ret){ //通信成功時の処理 }else{ //通信失敗時の処理 } } } ``` しょうがないので、「通信の処理だけ実装用のメソッドとして切り出し、 外部から渡せるようにする」という形で対処しようかなと思っています...。 以下のような感じにしようかなと思っています。 他に良い方法があったら、是非教えてください。 ``` php <?php //実際の通信処理を、このクラスに切り出す class SampleClassImpl{ HttpConnectionImpl(){ //通信系のAPIを呼ぶ処理 } } //親クラス class SampleClass{ //実際の通信処理を引数で取れるようにする(これでモックとして渡せる)。 HttpConnectionMethod($implMethod){ //引数で取ったメソッドを実行 $implMethod(); } } //テストしたいクラス class SampleSubClass extends SampleClass{ HttpConnectionMethod($implMethod){ $ret = parent::HttpConnectionMethod($implMethod); //戻り値に応じた事後処理 if($ret){ //通信成功時の処理 }else{ //通信失敗時の処理 } } } ```
th1209

2016/01/30 07:13

↑コメントだとMarkDown記法が効いてないみたいです。。。 見辛いですが、ご容赦ください><
deadcode

2016/01/31 17:02

土日にPC環境がなかったため、返信が遅れ申し訳ありません。 明日上記を確認して返信しようかと思います。 さらっと見た限りだとparentで呼んでいる部分を切り出して function httpConnectionCall() { return parent:: HttpConnectionMethod(); } みたいな形でSampleSubClassに作って、それをテスト対象のmethodから$this->httpConnectionCall();で呼び出す。 httpConnectionCallをmockを使って呼び出しとかすればいけそうな気がします。 明日になってしまい、遅れて申し訳ありませんが、確認させてください。
th1209

2016/02/01 06:49

deadcodeさん ご返信いただきありがとうございます (動作確認までしてくれるみたいで、ありがたい限りです...!) ご連絡いただいた方法だと、 親クラスに手を入れずに済むので、いいですよね! この方法なら、メソッドのモック作って差し替えることもできると思います。 ただ、親クラスにあるメソッドを、 そのままサブクラスでラップするって、なんだか悲しいですね。 こうでもしないとテストできないので、止むを得ませんが>< 本来なら、他APIと通信する処理や、DBの読み書きを行う処理は、 独立したクラスにして、委譲で保持すべきだったんでしょうね。 今後気をつけます^^; 明日確認してくださるとのことだったので、 コメントお待ちしていますね。 この方法で試してみて、 問題なければこの質問はクローズしたいと思います。
deadcode

2016/02/01 09:52

そうですね。先ほどチェックしてみたのですが、意図するものと同一かはちょっとわかりませんが、テストは通りました。 細かくいうとそれでは切り分けたhttpConnectionCallのテストはどうするんだという話にはなりますが・・・ ただ、callしているだけであれば親クラスの通信methodが正常にテストされていれば担保されていると考えて良いと思います。 あとは書かれているように親クラスに手を入れることはなるべくせずに解決できるならそちらをお勧めします。 確かに設計上見直すのであればSampleClassImplのように通信処理を切り出すのも手ですが、少し大掛かりなのと、この過程(テストを通すため)ではやらないほうが良いかと思います。
th1209

2016/02/02 12:53

deadcodeさん 返信が遅れてしまい、申し訳ありません。 実際の動作確認までしてくださり、ありがとうございます。 直し方ですが、おっしゃる通り、 通信処理を別クラスに切り出すのは難しいですよね...。 切り出してしまったら、対象のメソッドの呼び出し方法が変わってしまうので、 呼び出し元全部の引数の渡し方を変える必要があり、今回は断念しました。 こちらの疑問に対し、何度もご回答くださり、ありがとうございました。 おかげさまで、テストについて色々考えさせられました。 最近テスト作成でつまづくことが多いので、今後勉強していきたいなと思います...! またここで質問させて頂くことがあるかと思うのですが、どうか宜しくお願いします^^
deadcode

2016/02/02 13:06

自分も日々精進が必要な身です。 ここの質問に応えることによって勉強になることが多々あります。 何か有りましたらフォローしましたので回答依頼をしてみてください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問