web-dev-qa-db-ja.com

ユニットテストとサードパーティのパッケージ。あざけるかしないか?

ユニットテストに慣れてきました。新しいプロジェクトでは、TDDアプローチを採用することにしました。

以下のコードは、ユーザーの作成、ユーザーの削除、ユーザーの存在の確認などを行うUserServicesクラスをテストするためのものです。

私は正しい線にいますか?私が見ているところはどこでもモックについて説明しているので仕方がないので、predis(PHPのRedisとのやり取りに使用するパッケージ)をモックする必要があると思います。しかし、私のクラスはPredisのインスタンスを期待しているので、それをあざけるのは難しいでしょう。

セットアップでは、アクションを実行するダミーユーザーを作成します。複数作成する必要があるかもしれませんが、この段階では1つだけを使用します。ただし、まったく新しいユーザーを作成する必要があるcreateUserなどのメソッドがあります。

<?php

namespace VoteMySnap\Tests;

class UserServicesTest extends \PHPUnit_Framework_TestCase
{
    const Host = '127.0.0.1';
    const PORT = 6379
    const AUTH = NULL;

    public $predis;

    public function setUp()
    {
        $this->predis = new \PredisClient([
            'Host' => Host,
            'port' => PORT
        ]);

        /*
         * Create a dummy user
         */
        $dummyUser = [
            'user:1' => [
                'snapchat_username' => 'james16',
                'password' => 'somesecret',
                'email' => '[email protected]'
            ]
        ];

       /*
        * Insert user into Redis
        */ 
        $this->predis->hmSet(key($dummyUser), $dummyUser[key($dummyUser)]);
    }

    public function tearDown()
    {
        /*
         * Remove the dummy user
         */
        $this->predis->delete(key($dummyUser));
    }  
}

私はここで正しい軌道に乗っていますか?

4
BugHunterUK

私は常に、単体テストが1つのことだけをテストするという格言に従っています。各メソッドが1つのことだけを実行するようにプログラミングすると、そのメソッドの単体テストをかなり簡単に作成できるようになります。

メソッドが他のサービスまたはクラスを呼び出す場合は、それらをモックして、テスト中の動作が完全にわかるようにする必要があります。 PHPUnitを使用すると、PredisClientなど、使用しているパッケージ内のクラスを含むクラスをモックできます。 hmSetメソッドもモックしたいでしょう。 PHPUnitがこれをどのように実行するかを理解するために、以下を読むことをお勧めします。

https://phpunit.de/manual/current/en/test-doubles.html

また、コードをリファクタリングして、テストしているクラスの外でPredisClientをインスタンス化し(まだ行っていない場合)、コンストラクターパラメーターを介してそれをインジェクトすると、モックバージョンを簡単にインジェクトでき​​ます。 Dependency Injectionを検索して、これがどのように役立つかを確認してください!

2
Gruffputs

テストの際に私が固守しようとする原則の1つは 自分が所有していないものをモックしないでください です。

サードパーティのライブラリを使用している場合、可能性としては、ライブラリのすべてが必要ではなく、小さなサブセットのみである場合があります。また、そのライブラリのセマンティクスが独自のアプリケーションに浸透することを望まない場合もあります。これは、ライブラリの機能があなたの側でわずかに異なる用語で表現されているためです。

したがって、独自のアダプタクラス内に外部コンポーネントをラップします。アプリケーションのニーズを知っている機能だけを公開し、アプリケーションの他の部分と一貫性のある名前を付けます。テストや他の場所で他の実装を簡単に置き換えることができるように、そのラッパーの上に抽象化を置きます。

単体テストラッパーをスタブしてこれらの機能を使用するクラスですが、統合テスト可能であれば、実際のサードパーティモジュールに対するラッパー自体。

0
guillaume31

ユニットテストのすべてのケースで、ユニットとは何かを定義する必要があります。小さくしすぎると実用的でなく、大きくしすぎると役に立ちません。

マーティン・ファウラーはそれをクラスにすることを、時には(重要に)言います:

「私はしばしば密接に関連したクラスの束を取り、それらを単一のユニットとして扱います」

私は彼が彼のためのユニットがクラスであることを意味すると思います、しかし、時々、それが密結合の依存関係を含むならば、彼はユニットの一部としてそれらを考慮するでしょう。

自分で単体テストを難しくすることもできますし、実用的で簡単に生活を続けることができます。単体テストの全体のポイントは、コードが機能するかどうかを確認することです。したがって、この削除が難しい依存関係をテストに含めることができれば、依存オブジェクトまたはコードが原因でエラーが発生しているかどうかを判断できます。テストの実行は非常に高速で、大規模な設定は不要です...それで。

これらの条件のいずれかが当てはまらない場合は、それをモックする方法を理解するか、ユニットテストを無視して、すべての努力を統合テストに注ぎ込む必要があります(とにかく、ユニットテストはほんの少ししか実行できません)正しいシステムを作るために)

0
gbjbaanb