d + 20歳のプロジェクトを取得した、または来ましたか? PHPコードはマンモスの狩猟の間に書かれたので、軽く読まないのですか? あなたは少なくともそれを保存する必要があり、最大で-リファクタリングまたは書き換えますか?
これらの質問の後で、すぐに呼吸や脈拍がなかった場合は、この記事はすでにそのようないじめの犠牲者であるか、そのような運命の変化を予測している人を対象としています。
これは、この状況に典型的な特定のタスクの1つです。リファクタリングまたは変更の前に、ユニットをレガシーコードテストでカバーします。 つまり、関数やメソッドのスタブの作成(滴下、シミュレーションなど)をその場で実行します。
私の場合、主な問題である次の2つのソリューションを提供したいと思います。
1.スタブ関数のシーケンシャルリターン
public function getSomething($param1, $param2) { $result1 = mysql_query('SELECT * FROM table1'); // ... if ($result1['field'] == $param1) { $result2 = mysql_query('SELECT * FROM table2'); } // ... if ($result2['field'] == $param2) { $result3 = mysql_query('SELECT * FROM table3'); } // ... return isset($result3) ? $result3 : $result2; }
このようなコードをテストでカバーするには、いくつかのオプションがあります。
- リファクタリング、リクエストの削除、抽象化の記述、 PDOなど 理想的ですが、リファクタリングまでカバーしてから、すべてが同じように機能するようにする必要があります。
- 模擬データベース。 データベースのコピーを作成し、必要なレコードを「スリップ」できます。 しかし、数十個のテーブルとフィールドがあり、クエリが2-3結合よりも少し複雑な場合はどうでしょうか? 適切なデータのデバッグと作成には数日かかる場合があります。
- runkitまたはuopzを使用します。 おそらくこの状況で最も受け入れられるアプローチです。 しかし、呼び出しごとに異なる結果を作成する方法は?
2.テストされた機能に影響を与えないコードの実行
public function sendSomething(array $data) { $ch = curl_init(); $result = mysql_query('SELECT url FROM info WHERE id = ' . $data['someId']); curl_setopt($ch, CURLOPT_URL, $result['url']); curl_setopt($ch, CURLOPT_POSTFIELDS, implode('&', $data); // ... curl_exec($ch); } public function myMethod() { $data = SomeCLass::getSomeData(); // ... $data = OtherClass::modifyData($data); // ... // - , $data // ... $this->sendSomething($data); // ... return $completelyOtherVariable; }
オプション:
- ダミーのローカルURL? しかし、それはデータベースに「入れる」必要があり、他のチームメンバーは同じローカルホストを上げるか、現在のホストのアクセス可能なディレクトリにあるスクリプトを世界中にコミットする必要があります。
- runkitまたはuopzを介してmysql_queryおよびcurl_execをオーバーライドします。 はい、しかし、どのようにして一般に$データになったのかをどのように知るのですか
- sendSomethingメソッド全体をオーバーライドし、「 bind -it」を現在のスコープに匿名化して、そこにあるものを確認します
これらの例は主に「遠いところにある」ものですが、少なくとも私の実務ではある程度の類似性があります。 はい、より明確に。
ほとんどの場合、両方の場合でオプション#3を選択すると、これらすべてが最も簡単にパスします。 使用するもの、 runkitまたはwopzを決定する必要がありますか? 私にとって、答えは明白です。なぜなら、文字列にphpコードを記述して、それをパラメーターとして渡すのは、倒錯だからです。
使用するがネイティブではない主な機能:
void uopz_function ( string $class , string $function , Closure $handler [, int $modifiers ] )
彼女はとてもシンプルです。 これらの関数を報告します。これらの関数を再定義し、元の関数の代わりに実行される匿名関数を渡します。 そこにある関数のスコープを「再生」することもできますが、現在はそれについてではありません。
中間者+プログラマーは、次に何をすべきかをおおまかに把握しているので、これでやめることができますが、ジュニアは自殺の可能性が高いため、そのようなタスクをほとんど任せられません。
この記事は、囚人の作業をわずかにスピードアップし、彼のコードをもう少し読みやすく、短くすることのみを目的としています。
したがって、2つのことを提供したいと思います。
- トピックに関する聖戦:「どこで、どのように、いつ形質を正しく使用するか」。
- いくつかの便利なメソッドが実装されているuopzの特性ラッパー
すべてのコードを複製するのではなく、ここにgithubへのリンクを残してください。 また、便宜上、彼のメソッドを簡単にリストします。
uopzFlags($function, $flags); // uopzRedefine($constant, $value); // uopzFunction($function, Closure $closure, $backup = false); // "" uopz_function , backup- : 'mysql_query' ['ClassName', 'methodName'] uopzMuteFunction($function, $backup = false); // -, , , - , curl "" url, etc uopzRestore($function); // backup- uopzBackup($function); // backup / ( ) uopzFunctionSimpleReturn($function, $return, $backup = false); // . return , ( ) . uopzFunctionReplace($function, $replace, $backup = false); // . uopzFunctionConsistentReturn($function, array $return, $backup = false); // . , . , . uopzFunctionConditionReturn($function, array $conditionList, $default = null, $backup = false); // . . uopzFunctionHook($function, Closure $closure, &$return, $backup = false); // .
さて、そして実際には、「これ」の助けを借りたこれらの2つの問題の解決策:
1.シーケンシャルリターン
$this->uopzFunctionConsistentReturn('mysql_query', [ ['id' => 12, 'data' => 'dummy'], ['id' => 31, 'data' => 'dummy'], ['id' => 45, 'data' => 'dummy'], ]); // , , ( , ): $this->uopzFunctionConditionReturn('mysql_query', [ ['query', 'SELECT * FROM table1', ['id' => 12, 'data' => 'dummy']], ['query', 'SELECT * FROM table2', ['id' => 31, 'data' => 'dummy']], ['query', 'SELECT * FROM table3', ['id' => 45, 'data' => 'dummy']], ]);
2.傍受の実行
$this->uopzFunctionHook( ['ClassName', 'sendSomething'], function() { return $data; }, // $data // , myMethod sendSomething $data );
時間を大幅に節約できたので、共有することにしました。 誰かがこれも役に立つと思います。 そして、世界では毎日、そのようなコードがますます少なくなり、それが有用になることを願っています:)
ご清聴ありがとうございました。