10

それで、私はグーグルのテストブログを読んでいました、そしてそれはグローバルな状態が悪くてテストを書くのを難しくしていると言います。私はそれを信じています-私のコードは今テストするのが難しいです。では、どうすればグローバル状態を回避できますか?

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

私の関数のいくつかはグローバル変数に依存しています。したがって、関数をテストするときは、最初に特定のグローバルを設定することを忘れないでください。そうしないと、テストが失敗します。これは避けたいです。

状態情報を管理する良い方法はありますか?(または、グローバル状態を誤って理解していますか?)

4

4 に答える 4

12

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

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

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

于 2008-09-04T18:18:03.150 に答える
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 を使用するよりも優れていると思います。

于 2008-09-04T19:26:21.613 に答える
1

素晴らしい最初の質問。

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

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

于 2008-09-04T18:33:57.763 に答える
0

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

index.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(データアクセスオブジェクト)オブジェクトに依存するサービスレイヤーオブジェクトに依存します

于 2014-01-31T01:15:31.720 に答える