0

ユーザープロファイルを作成するコントローラーは、ユーザーが自分のプロファイルをアップロードしないことを選択した場合に表示および使用されるデフォルトのロゴ(PNG)であるプロファイルビューモデルの一部を使用しています。

public static class Configurationプロジェクトのすべての定数を保持するものを作成しました。定数の1つは、デフォルトのロゴに使用されるファイル名と場所です。

ハードコードされた定数ではなく、実際のファイル名をWeb.Configファイルに保持しますいくつかの理由により:1。ファイル名が変更される可能性があります2.ファイルの場所が変更される可能性があります

コントローラをテストする最初の試みは、をWeb.Config呼び出してアクセスする定数クラスで失敗しましたConfigurationManager.AppSettings。ここの人々は(非常に正当にそうですが)これは避けるべき別の依存関係であると私に言いました。一方、これは単なる外部化された定数であり、このようにハードコーディングしておくのは好きではありませんFile f = new File("..\\Images\\Profile\\DefaultLogo.PNG");。誰もこれらのことをしません、そしてそれは構成可能でなければなりません(つまりWeb.Config-私が間違っているなら私を訂正してください)。

状況に対処するためのあなたの推奨事項は何ですか?

質問を編集する質問 を繰り返します。使用する形式ではなく、コントローラーTDDをテスト可能にして、定数をアーキテクチャーから除外するというジレンマに対処する方法です。(現在、静的クラスを使用しているため、コントローラーが必要とするすべての定数をコンストラクターで手動で渡す必要があります。これは、可能な限り最良のオプションのようには見えません)

  • 定数をハードコーディングする(するのが嫌い)
  • コントローラからビューモデルに移動します(TDDの問題は解決しないと思います)
  • IConfigurationコントローラに別のインターフェイス抽象化( )があります(IRepository私には醜いようです)-さらに、Configクラスは静的であり、インターフェイスを実装できないため、機能しません
  • 思いもよらなかったので、明るいアイデアを求めました。

どうもありがとうございます

4

1 に答える 1

2

IRepository(私には醜いように見えます)と一緒にコントローラーに別のインターフェイス抽象化(IConfiguration)があります-さらに、Configクラスは静的であり、インターフェイスを実装できないため、機能しません

太字の記述は完全に真実ではありません。例えば:

public interface IManageConfigurations
{
    string DefaultFileLocation { get; }
}

public class ConfigurationManagerImpl : IManageConfigurations
{
    public string DefaultFileLocation
    {
        get { return ConfigurationManager.AppSettings["DefaultFileLocation"]; }
    }
}

public class MyController : Controller
{
    private readonly IRepository _repository;
    private readonly IManageConfigurations _config;

    public MyController(IRepository repository, IManageConfigurations config)
    {
        _repository = repository;
        _config = config;
    }
}

これは醜い解決策ではないと思いますが、それは主に主観的な美的意見です。ほとんどの場合、インターフェイスの依存関係が約5つ以上になるまで、クラスがオーバーインジェクションのアンチパターンを明らかにすることは考えていません。

さらに、これは、ユニットでテスト可能なコードの依存関係を解決するためのほぼ標準的なソリューションです。リポジトリをモックアウトするのと同じように、構成インターフェースをモックアウトできます。上記は、web.configに保持されている値を使用して依存関係を解決する方法です。

もう1つの解決策はConfigurationManager.AppSettings["key"]、コントローラーで呼び出しをハードコーディングすることです。次に、単体テストプロジェクトで、app.configファイルに同じ値を設定できます。次に、単体テストランナーはapp.configで値を検索しますが、Webサーバーはweb.configで値を検索します。

public class MyController : Controller
{
    public ActionResult Index()
    {
        // the below will get the value from the unit test project's app.config
        // when run as a unit test, but will get the value from web.config in server
        var fileLocation = ConfigurationManager.AppSettings["DefaultFileLocation"];
    }
}

アップデート

文字列を静的クラスに保持し、ユニットをテスト可能なコードにしたい場合は、次のように実行できます。

public static class ConfigSettings
{
    public static string DefaultFileLocation
    {
        get { return ConfigurationManager.AppSettings["DefaultFileLocation"]; }
    }
}

その後、その静的クラスを内から自由に使用できますController。ただし、単体テストとして実行するときに値を提供するには、前述のように、Webプロジェクトのファイルにノードがあるのと非常によく似たappSettingsノードを単体テストプロジェクトのファイルに配置する必要があります。単体テストランナーはapp.configから値をプルし、Webサーバーはweb.configから値をプルします。app.configappSettingsweb.config

UnitTestProject \ app.config

<configuration>
    <appSettings>
        <!-- use this value when executed in unit test runner -->
        <add key="DefaultFileLocation"
            value="C:\Users\me\test_files\test_file.png" />
    </appSettings>
</configuration>

MvcProject \ web.config(デフォルト)

<configuration>
    <appSettings>
        <!-- use this value when executed locally in IIS Express -->
        <add key="DefaultFileLocation"
            value="C:\Users\me\Documents\Visual Studio 20xx\Projects\MyProj\App_Data\default_files\default_logo.png" />
    </appSettings>
</configuration>

MvcProject \ web.Release.config(変換)

<configuration>
    <appSettings>
        <!-- use this value when executed on live IIS production server -->
        <add key="DefaultFileLocation"
            value="E:\approot\siteroot\App_Data\default_files\default_logo.png"
            xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
    </appSettings>
</configuration>

これがあなたの質問に答えない場合、おそらく私はあなたが何を求めているのかまだ完全には理解していません。

アップデート

私はあなたのソリューションに1つだけ欠けています-コントローラー内からそのパブリック静的クラスConfigSettingsを使用する方法は?この静的クラスをパラメーターとしてコンストラクターに渡す必要がありますか?

いいえ、特別なことをする必要はありません。staticを使用するのと同じように、クラスとして使用するだけですConfigurationManager

public ActionResult MyAction()
{
    var customFilePath = GetCustomFilePath(); // may not be set
    if (string.IsNullOrWhiteSpace(customFilePath)) // fall back to default
        customFilePath = ConfigSettings.DefaultFilePath;
}

したがって、コントローラーアクションは静的ConfigSettingsクラスに依存しますが、この場合は注入可能/スワップ可能な依存関係ではありません。単体テストランナーがこのメソッドを呼び出し、customFilePathがnull /空/空白の場合、ConfigSettings getメソッドにステップインし、ConfigurationManager.AppSettingsを呼び出します。このメソッドは、単体テストプロジェクトのapp.config/appSettingsで値を検索します。 。

于 2013-03-24T13:36:48.677 に答える