web-dev-qa-db-ja.com

ConfigurationManager.AppSettingsが単体テストプロジェクトでNullを返す

app.configファイルにアプリケーション設定を含むC#単体テストプロジェクトがあります。別のプロジェクトに存在するクラスをテストしています。そのクラスは、ConfigurationManager.AppSettingsConfigurationManager.ConnectionStringsの両方に依存しています。

テスト対象のクラスが存在するプロジェクトには、app.configファイルがありません。クラスは単体テストプロジェクトのコンテキストでインスタンス化されているため、単体テストプロジェクトのapp.configファイルを使用すると考えていました。実際、これは接続文字列の場合に当てはまるようです。

クラスは問題なく接続文字列を取得します。ただし、クラスがアプリケーション設定を取得しようとすると、構成マネージャーは常にnullを返します。ここで何が起こっているのですか?

編集1

何が起こるかを確認するために、テストプロジェクトにいくつかの設定をロードしてみるのは良い考えだと思いました。外部プロジェクトでクラスをインスタンス化するコードを呼び出す直前に、ユニットテストで設定をロードしようとしました。同じ結果、何もありません。とりあえず、他のプロジェクトを方程式から除外できると思います。

これが私の設定ファイルからの抜粋です:

<configSections>
  <sectionGroup name="applicationSettings"
                type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
    <section name="MyNamespace.Properties.Settings"
             type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
             requirePermission="false" />
  </sectionGroup>
</configSections>

...

<applicationSettings>
  <MyNamespace.Properties.Settings>
    <setting name="Bing_Key"
             serializeAs="String">
      <value>...</value>
    </setting>
  </MyNamespace.Properties.Settings>
</applicationSettings>

そしてこれが私が設定をロードしようとしている方法です:

string test = System.Configuration.ConfigurationManager.AppSettings["Bing_Key"];
19
Jason Boyd

プロジェクトのプロパティで設定について説明しました。この方法で設定にアクセスできるかどうかを確認します。

string test = Properties.Settings.Default.Bing_Key;

プロジェクト設定ファイルが定義されている実行中のアセンブリを取得する必要があるかもしれませんが、これを最初に試してください。

編集

Visual Studioのプロジェクト設定ファイルを使用すると、app.configに要素が追加され、存在しない場合はapp.configが作成されます。 ConfigurationManagerはこれらの設定を変更できません!上記の静的メソッドを使用しないと、これらの特定の生成されたproject.settingsファイルにアクセスできません。 ConfigurationManagerを使用する場合は、app.configを手書きする必要があります。次のように設定を追加します。

<appSettings>
  <add key="bing_api" value="whatever"/>
</appSettings>
7
Bill Sambrone

ラッパーを使用するために構成にアクセスするコードをリファクタリングすることを検討してください。その後、ラッパークラスのモックを記述でき、テスト用の構成ファイルのインポートを処理する必要がありません。

両方に共通のライブラリーには、次のようなものがあります。

public interface IConfigurationWrapper {

    string GetValue(string key);
    bool HasKey(string key);
}

次に、configにアクセスする必要があるライブラリで、このインターフェースタイプのインスタンスを、configを読み取る必要があるクラスに挿入します。

public class MyClassOne {

    private IConfigurationWrapper _configWrapper;

    public MyClassOne(IConfigurationWrapper wrapper) {
        _configWrapper = wrapper;
    } // end constructor

    public void MethodThatDependsOnConfiguration() {
        string configValue = "";
        if(_configWrapper.HasKey("MySetting")) {
            configValue = _configWrapper.GetValue("MySetting");
        }
    } // end method

} // end class MyClassOne

次に、ライブラリの1つで、構成ファイルに依存する実装を作成します。

public class AppConfigWrapper : IConfigurationWrapper {

    public string GetValue(string key) {
        return ConfigurationManager.AppSettings(key);
    }

    public bool HasKey(string key) {
       return ConfigurationManager.AppSettings.AllKeys.Select((string x) => x.ToUpperInvariant()).Contains(key.ToUpperInvariant());
    }
}

次に、クラスを呼び出すコードで。

//Some method container
MyClassOne dataClass = new MyClassOne(new AppConfigWrapper());

dataClass.MethodThatDependsOnConfiguration();

その後、テストでは、依存関係の束縛から解放されます。 :) IConfigurationWrapperを実装する偽のバージョンを作成し、それをテストのために渡すことができます。ここで、GetValueおよびHasKey関数からの戻り値をハードコードします。 Moqのようなモックライブラリを使用:

Mock<IConfigurationWrapper> fakeWrapper = new Mock<IConfigurationWrapper>();

fakeWrapper.Setup((x) => x.GetValue(It.IsAny<string>)).Returns("We just bypassed config.");

MyClassOne testObject = new MyClassOne(fakeWrapper.Object);
testObject.MethodThatDependsOnConfiguration();

コンセプトをカバーする記事を次に示します(ただし、Webフォームの場合でも、コンセプトは同じです)。 http://www.schwammysays.net/how-to-unit-test-code-that-uses -appsettings-from-web-config /

11
xDaevax

そして彼は「NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO」と叫んだ。

Cite:app.configファイルにアプリケーション設定を含むC#単体テストプロジェクトがあります。別のプロジェクトに存在するクラスをテストしています。そのクラスは、ConfigurationManager.AppSettingsとConfigurationManager.ConnectionStringsの両方に依存します。

あなたはこれをしません。エバー!!!!どうして?これで依存関係が作成されました。代わりに、依存関係の注入を使用して、アプリケーションに属する構成ファイルにピークを設定することなく、クラスがその作業を実行できるようにします。

0