いくつかの追加機能を追加する HttpApplication から派生したクラスがあります。これらの機能を単体テストする必要があるところまで来ました。つまり、HttpApplication の新しいインスタンスを作成し、リクエストを偽造し、レスポンス オブジェクトを取得できる必要があります。
HttpApplication オブジェクトの単体テストを正確に行うにはどうすればよいですか? 現在 Moq を使用していますが、必要なモック オブジェクトを設定する方法がわかりません。
いくつかの追加機能を追加する HttpApplication から派生したクラスがあります。これらの機能を単体テストする必要があるところまで来ました。つまり、HttpApplication の新しいインスタンスを作成し、リクエストを偽造し、レスポンス オブジェクトを取得できる必要があります。
HttpApplication オブジェクトの単体テストを正確に行うにはどうすればよいですか? 現在 Moq を使用していますが、必要なモック オブジェクトを設定する方法がわかりません。
残念ながら、これは特に簡単なことではありません。HttpApplicationは、モックを作成するのが簡単ではないためです。モックするインターフェースはなく、ほとんどのメソッドは仮想としてマークされていません。
最近、HttpRequestとHttpWebResponseで同様の問題が発生しました。結局、私が求めた解決策は、使用したいメソッドのストレートな「パススルー」ラッパーを作成することでした。
public class HttpWebRequestWrapper : IHttpWebRequestWrapper
{
private HttpWebRequest httpWebRequest;
public HttpWebRequestWrapper(Uri url)
{
this.httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);
}
public Stream GetRequestStream()
{
return this.httpWebRequest.GetRequestStream();
}
public IHttpWebResponseWrapper GetResponse()
{
return new HttpWebResponseWrapper(this.httpWebRequest.GetResponse());
}
public Int64 ContentLength
{
get { return this.httpWebRequest.ContentLength; }
set { this.httpWebRequest.ContentLength = value; }
}
public string Method
{
get { return this.httpWebRequest.Method; }
set { this.httpWebRequest.Method = value; }
}
public string ContentType
{
get { return this.httpWebRequest.ContentType; }
set { this.httpWebRequest.ContentType = value; }
}
}
などなど
これにより、自分のラッパーインターフェイスをあざけることができました。必ずしも世界で最もエレガントなものではありませんが、フレームワークの「モック可能」ではない部分のいくつかをモックアウトするための非常に便利な方法です。
ただし、急いでこれを行う前に、取得したものを確認し、クラスをラップする必要がない、テストへのより良いアプローチがあるかどうかを確認することをお勧めします。
HttpWebRequest、HttpApplicationなどの場合、IMHOがないことがよくあります。
このラッパーをモックに設定するには(上記のHttpWebRequestの例を使用)、Moqを使用して次のような操作を行います。
var mockWebRequest = new Mock<IHttpWebRequestWrapper>();
mockWebRequest.SetupSet<string>(c => c.Method = "POST").Verifiable();
mockWebRequest.SetupSet<string>(c => c.ContentType = "application/x-www-form-urlencoded").Verifiable();
mockWebRequest.SetupSet<int>(c => c.ContentLength = 0).Verifiable();
HttpApplicationを拡張して機能を追加するIMHOは、最善の方法ではありません。プライベート/内部/封印されたクラスのためにHttpContextをモックするのは非常に難しいため、ユニットテストに成功しても、モックコードが乱雑になり、実際に何をテストしているのか理解できなくなります。
追加する機能について詳しく教えてください。この機能をアプリケーションに追加するためのより良い方法があるかもしれません。
Microsoft Moles を使用した非常に優れたアプローチを説明している次のブログを以前に見つけました。
http://maraboustork.co.uk/index.php/2011/03/mocking-httpwebresponse-with-moles/
要するに、ソリューションは次のことを示唆しています。
[TestMethod]
[HostType("Moles")]
[Description("Tests that the default scraper returns the correct result")]
public void Scrape_KnownUrl_ReturnsExpectedValue()
{
var mockedWebResponse = new MHttpWebResponse();
MHttpWebRequest.AllInstances.GetResponse = (x) =>
{
return mockedWebResponse;
};
mockedWebResponse.StatusCodeGet = () => { return HttpStatusCode.OK; };
mockedWebResponse.ResponseUriGet = () => { return new Uri("http://www.google.co.uk/someRedirect.aspx"); };
mockedWebResponse.ContentTypeGet = () => { return "testHttpResponse"; };
var mockedResponse = "<html> \r\n" +
" <head></head> \r\n" +
" <body> \r\n" +
" <h1>Hello World</h1> \r\n" +
" </body> \r\n" +
"</html>";
var s = new MemoryStream();
var sw = new StreamWriter(s);
sw.Write(mockedResponse);
sw.Flush();
s.Seek(0, SeekOrigin.Begin);
mockedWebResponse.GetResponseStream = () => s;
var scraper = new DefaultScraper();
var retVal = scraper.Scrape("http://www.google.co.uk");
Assert.AreEqual(mockedResponse, retVal.Content, "Should have returned the test html response");
Assert.AreEqual("http://www.google.co.uk/someRedirect.aspx", retVal.FinalUrl, "The finalUrl does not correctly represent the redirection that took place.");
}