11

次のコントローラーアクションがあります

public void Post(Dto model)
{
    using (var message = new MailMessage())
    {
        var link = Url.Link("ConfirmAccount", new { model.Id });

        message.To.Add(model.ToAddress);
        message.IsBodyHtml = true;
        message.Body = string.Format(@"<p>Click <a href=""{0}"">here</a> to complete your registration.<p><p>You may also copy and paste this link into your browser.</p><p>{0}</p>", link);

        MailClient.Send(message);
    }
}

これをテストするには、コントローラーのコンテキストをセットアップする必要があります

var httpConfiguration = new HttpConfiguration(new HttpRouteCollection { { "ConfirmAccount", new HttpRoute() } });
var httpRouteData = new HttpRouteData(httpConfiguration.Routes.First());
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "http://localhost");
sut = new TheController
{
    ControllerContext = new HttpControllerContext(httpConfiguration, httpRouteData, httpRequestMessage),
    MailClient = new SmtpClient { PickupDirectoryLocation = location }
};

これは、リンクの作成をテストするための多くのセットアップのようです。これを行うためのよりクリーンな方法はありますか?インメモリサーバーについて読んだことがありますが、コントローラーを直接テストするよりもhttpclientに適用されるようです。

4

3 に答える 3

16

私は Web API 2.0 でこのアプローチを使い始めました。

モック ライブラリを使用している場合 (実際のユニット テストでは実際に使用する必要があります)、UrlHelperオブジェクトのすべてのメソッドが.xml であるため、オブジェクトを直接モックできますvirtual

var mock = new Mock<UrlHelper>();
mock.Setup(m => m.Link(It.IsAny<string>(), It.IsAny<object>())).Returns("test url");

var controller = new FooController {
    Url = mock.Object
};

これは Ben Foster の回答よりもはるかにクリーンなソリューションです。そのアプローチでは、使用しているすべての名前の構成にルートを追加する必要があります。それは簡単に変更されるか、設定するルートが途方もなく多くなる可能性があります。

于 2015-09-16T14:07:16.310 に答える
2

私は同じばかげたことに遭遇しています。私が見つけることができるすべての参照は、リクエスト/コントローラーをモックすることを望んでいます。これは(あなたが指摘したように)多くの作業です。

特定の参照:

私は実際のモッキング フレームワークを試していないので、コントローラーを「ビルド」するためのヘルパー クラスがあります。だから代わりに

sut = new TheController { ... }

私は次のようなものを使用します:

// actually rolled together to `sut = MyTestSetup.GetController(method, url)`
sut = new TheController()...
MyTestSetup.FakeRequest(sut, HttpMethod.Whatever, "~/the/expected/url");

参考までに、方法は基本的に次のとおりです。

public void FakeRequest(ApiController controller, HttpMethod method = null, string requestUrl = null, string controllerName = null) {
    HttpConfiguration config = new HttpConfiguration();
    // rebuild the expected request
    var request = new HttpRequestMessage( null == method ? this.requestMethod : method, string.IsNullOrWhiteSpace(requestUrl) ? this.requestUrl : requestUrl);
    //var route = System.Web.Routing.RouteTable.Routes["DefaultApi"];
    var route  = config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}");

    // TODO: get from application?  maybe like https://stackoverflow.com/a/5943810/1037948
    var routeData = new HttpRouteData(route, new HttpRouteValueDictionary { { "controller", string.IsNullOrWhiteSpace(controllerName) ? this.requestController : controllerName } });

    controller.ControllerContext = new HttpControllerContext(config, routeData, request);

    // attach fake request
    controller.Request = request;
    controller.Request.Properties[/* "MS_HttpConfiguration" */ HttpPropertyKeys.HttpConfigurationKey] = config;
}
于 2012-08-20T19:52:53.447 に答える