はじめに
久々にPHPの酷いコードにテストを足したのでまとめるよ。
患者さん事例
PHPって地の文ベタ書きで全然かけてしまう。
なので雑に書いたコードが適当なフォルダに突っ込まれていて、それをApatchが直接参照していたりするわけだ。
拡張されまくったり炎上したりで結果的にとんでもなく酷いコードが出来上がる。
そう、こんな感じに。
<?php
require_once "External.php"; // global変数定義
// おもむろに追加された認証ロジック
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
// 業務ロジック
echo "<html>";
if (/* なんかややこしい判定 */) {
echo "へんなとこでボディを返したり";
if (/* if文の深淵で */){ exit; } // なんてされてたら目も当てられない
}
else{
header("クレイジーなところでヘッダを返していたりする");
}
echo "</html>";
}
else {
// 業務ロジック
echo "<html>どうのこうの</html>";
}
テストコードを加えたいところだがこのままでは無理だ。
なので最低限の修正でテスト可能にしておこう。
地の文いきなり走り出す問題の対処
最悪なことに地の文は読み込まれても実行されてしまう。だからまずはそれを封じる必要がある。
<?php
require_once "product code"; // ここでプロダクトコードが動いてしまう!
class IndexTest extends TestCase
{
public function testPostWithNoParameter()
{
/* ここで実行したいのに! */
}
}
これはもうなんともできんのでプロダクトコードに変更を加える。
<?php
require_once "External.php"; // global変数定義
function run($globalVarA, $globalVarB)
{
// 元あった地の文
}
if (http_response_code() !== false) {
run($globalVarA, $globalVarB);
}
末尾のIF判定のおかげでUT実行時は run
は実行されない。
(もっといいアイデアがあればよこしやがってください)
注意したいのはグローバル変数で、それだけで死刑に相当するのだが今は粛清より修正だ。
こればっかりは埋まっているのを探し当てるしか無い。最もリスクのある部分。
これで一旦画面ポチポチしなくてもUTから run
をけるだけでテストできるようになった。
echo/headerの追放
コイツラはapatch側に処理を返しているデータだ。
だからUTでこの値をチェックしたい。なので run
の返り値にしてやろうじゃないか。
<?php
require_once "External.php"; // global変数定義
class HttpResponse
{
// なんかいい感じに定義
};
function run($globalVarA, $globalVarB)
{
$headers = [];
$contents = [];
// 元あった地の文
// header(xxx); => $headers[] .= xxx;
// echo xxx; => $contents .= xxx;
return new HttpResponse($headers, $contents);
}
if (http_response_code() !== false) {
$httpResponse = run($globalVarA, $globalVarB);
foreach($httpResponse->headers as $header) {
header($header);
}
echo $httpResponse->body();
}
サーバから渡ってくる値も変えたいな
サーバから渡ってくる色んな値を想定してテストしたいよね?
だから引数で渡せるようにしよう。
<?php
require_once "External.php"; // global変数定義
class HttpResponse
{
// なんかいい感じに定義
};
function run(
$globalVarA,
$globalVarB,
$requestMethod,
$requestParameter,
/* 他にあればどうぞ */
) {
$headers = [];
$contents = [];
// 元あった地の文
// header(xxx); ---> $headers[] .= xxx;
// echo xxx; ---> $contents .= xxx;
return new HttpResponse($headers, $contents);
}
if (http_response_code() !== false) {
$httpResponse = run(
$globalVarA,
$globalVarB,
$_SERVER['REQUEST_METHOD'],
$_RESUEST,
/* 他にあればどうぞ */
);
foreach($httpResponse->headers as $header) {
header($header);
}
echo $httpResponse->body();
}
まぁだいたいこんな感じです。
その他
- run関数をクラス化したかったらする(自分は関数でいいと思う)
- CookieやSessionの情報もちゃんと切り出す