私はいくつかの単体テストを行っており、Moqを使用していくつかのプロパティをモックしています。
現在、これはControllerテスト(ASP.NET MVC 3)です。私のコントローラーは、AbstractControllerと呼ばれるabstractコントローラーから派生します。
このコントローラーは、Httpコンテキストに依存しています(テーマ設定、HTTPホストヘッダーに基づくドメイン固有のロジックなどを実行するため)。
これはWebSiteSettingsと呼ばれるプロパティを介して行われます:
public abstract class AbstractController : Controller
{
public WebSiteSettings WebSiteSettings { get; private set; }
// other code
}
プライベートセットに注意してください-アクターがセットアップします。それで、インターフェイスを使用するように変更しました。
public IWebSiteSettings WebSiteSettings { get; private set; }
次に、「FakeWebSiteSettings」を作成しました。これは、HTTPヘッダーを読み取るためにHttpコンテキストをモックします。
問題は、テストを実行するとNotSupportedException:が返されることです。
非仮想(VBでオーバーライド可能)メンバーでの無効なセットアップ:x => x.WebSiteSettings
関連するモックコードは次のとおりです。
var mockWebSiteSettings = new Mock<FakeWebSiteSettings>();
var mockController = new Mock<MyController>(SomeRepository);
mockController.Setup(x => x.WebSiteSettings).Returns(mockWebSiteSettings.Object);
_controller = mockController.Object;
var httpContextBase = MvcMockHelpers.FakeHttpContext();
httpContextBase.Setup(x => x.Request.ServerVariables).Returns(new NameValueCollection
{
{"HTTP_Host","localhost.www.mydomain.com"},
});
_controller.SetFakeControllerContext(httpContextBase.Object);
WebsiteSettings
プロパティを作成するとvirtual-テストに合格します。
しかし、なぜこれを行う必要があるのか理解できません。私は実際にプロパティをオーバーライドしません、私は単にそれがどのように設定されているかをockしています。
私は何かを見逃していますか、これを間違っていますか?
Moqおよび他の同様のモックフレームワークは、インターフェイス、抽象メソッド/プロパティ(抽象クラス)、または仮想クラス/具象クラスのプロパティのみをモックできます。
これは、呼び出しをインターセプトするために、インターフェイスを実装するプロキシを生成するか、これらのオーバーライド可能なメソッドをオーバーライドする派生クラスを作成するためです。
インターフェイスとラッパークラスを作成しました。例えば.
public interface IWebClient
{
string DownloadString(string url);
}
public class WebClient : IWebClient
{
private readonly System.Net.WebClient _webClient = new System.Net.WebClient();
public string DownloadString(string url)
{
return _webClient.DownloadString(url);
}
}
そして、ユニットテストでインターフェースをモックアウトするだけです:
var mockWebClient = new Mock<IWebClient>();
明らかに、より多くのプロパティ/メソッドを含める必要があるかもしれません。しかし、トリックを行います。
現在の日付時刻の変更など、他のモックの問題に対する別の便利なトリック(私は常にUTC日付時刻を使用します):
public interface IDateTimeUtcNowProvider
{
DateTime UtcNow { get; }
}
public class DateTimeUtcNowProvider : IDateTimeUtcNowProvider
{
public DateTime UtcNow { get { return DateTime.UtcNow; } }
}
例えばx分ごとに実行されるサービスがある場合は、IDateTimeProviderをモックアウトし、後で実行されたサービスを再度チェックするための時間を返すことができます。
「だから...私がしたことは唯一の方法ですか?」
唯一の方法ではありません-インターフェイスを実装して、それをock笑する方がずっと良いです。その後、実際のメソッドは、選択したとおりに仮想化することもできます。
前に述べたことはすべて真実ですが、プロキシモッキングアプローチ(moqが使用するアプローチなど)が唯一のアプローチではないことを知っておく価値があります。
http://www.typemock.com/ をチェックすると、包括的なソリューションが得られます。これにより、シールドクラス、非仮想メソッドなどの両方をモックできます。かなり強力です。