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.config
appSettings
web.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で値を検索します。 。