質問

そこで、Google のテストに関するブログを読んでいたのですが、グローバルな状態が悪く、テストを書くのが難しくなっていると書かれていました。私はそれを信じています。私のコードは現時点ではテストするのが困難です。では、グローバル状態を回避するにはどうすればよいでしょうか?

私が (私が理解しているところによると) グローバル状態を使用する最大の目的は、開発環境、受け入れ環境、運用環境の間で重要な情報を管理することです。たとえば、「Globals」という名前の静的クラスがあり、「DBConnectionString」と呼ばれる静的メンバーがあります。アプリケーションが読み込まれると、ロードする接続文字列を決定し、Globals.dbconnectionStringに入力します。ファイル パス、サーバー名、その他の情報を Globals クラスにロードします。

私の関数の一部はグローバル変数に依存しています。したがって、関数をテストするときは、最初に特定のグローバルを設定することを忘れないようにする必要があります。そうしないと、テストが失敗します。これは避けたいのですが。

状態情報を管理する良い方法はありますか?(それともグローバル状態を間違って理解しているのでしょうか?)

役に立ちましたか?

解決

依存関係の注入はあなたが探しているものです。これらの関数を実行して依存関係を探すのではなく、依存関係を関数に注入します。つまり、関数を呼び出すと、必要なデータが関数に渡されます。そうすれば、必要に応じてモック オブジェクトを挿入するだけで済むため、クラスの周りにテスト フレームワークを配置するのが簡単になります。

一部のグローバル状態を回避するのは困難ですが、これを行うための最良の方法は、アプリケーションの最上位レベルでファクトリ クラスを使用し、その最上位レベルより下のすべては依存関係の注入に基づいています。

2 つの主な利点:1 つ目は、テストが非常に簡単になること、2 つ目は、アプリケーションがより疎結合になることです。クラスの実装ではなく、クラスのインターフェイスに対してプログラミングできることに依存します。

他のヒント

テストにデータベースやファイルシステムなどの実際のリソースが含まれる場合、実行していることは次のとおりであることに注意してください。 統合テスト それよりも 単体テスト. 。統合テストには事前設定が必要ですが、単体テストは独立して実行できる必要があります。

Castle Windsor などの依存関係注入フレームワークの使用を検討することもできますが、単純なケースでは、次のような中道アプローチを取ることができる場合があります。

public interface ISettingsProvider
{
    string ConnectionString { get; }
}

public class TestSettings : ISettingsProvider
{        
    public string ConnectionString { get { return "testdatabase"; } };
}

public class DataStuff
{
    private ISettingsProvider settings;

    public DataStuff(ISettingsProvider settings)
    {
        this.settings = settings;
    }

    public void DoSomething()
    {
        // use settings.ConnectionString
    }
}

実際には、実装内の構成ファイルから読み取ることになる可能性が最も高くなります。その気になれば、スワップ可能な構成を備えた本格的な DI フレームワークが最適ですが、少なくとも Globals.ConnectionString を使用するよりは優れていると思います。

素晴らしい最初の質問です。

短い答え:アプリケーションがすべての入力 (暗黙的なものを含む) から出力まで関数であることを確認してください。

あなたが説明している問題はグローバルな状態ではないようです。少なくとも可変状態ではありません。むしろ、あなたが説明していることは、よく「構成の問題」と呼ばれるもののようであり、多くの解決策があります。Java を使用している場合は、次のような軽量のインジェクション フレームワークを検討するとよいでしょう。 ガイス. 。Scala では、これは通常次のように解決されます。 暗黙的に. 。一部の言語では、別のプログラムをロードして、実行時にプログラムを構成できます。これは、Smalltalk で書かれたサーバーを構成する方法であり、私は Xmonad と呼ばれる Haskell で書かれたウィンドウ マネージャーを使用しています。その構成ファイルは単なる別の Haskell プログラムです。

MVC 設定での依存関係注入の例は次のとおりです。

インデックス.php

$container = new Container();
include_file('container.php');

コンテナ.php

container.add("database.driver", "mysql");
container.add("database.name","app");

...

$container.add(new Database($container->get('database.driver', "database.name")), 'database');
$container.add(new Dao($container->get('database')), 'dao');
$container.add(new Service($container->get('dao')));
$container.add(new Controller($container->get('service')), 'controller');

$container.add(new FrontController(),'frontController');

Index.php の続きは次のとおりです。

$frontController = $container->get('frontController');
$controllerClass = $frontController->getController($_SERVER['request_uri']);
$controllerAction = $frontController->getAction($_SERVER['request_uri']);
$controller = $container->get('controller');
$controller->$action();

コントローラーは、データベースドライバー、名前などに依存するデータベースオブジェクトに依存するDAO(Data Accessオブジェクト)オブジェクトに依存するサービスレイヤーオブジェクトに依存します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top