2

ここを使用してアカウントコントローラーをテストしようとしてMoqいますが、これは私が行ったことです

コントローラ

   private readonly IWebSecurity _webSecurity;
    public AccountController(IWebSecurity webSecurity)
    {
        this._webSecurity = webSecurity;
    }
    public ActionResult Login(LoginModel model, string returnUrl)
    {
        if (ModelState.IsValid && _webSecurity.login(model))
        {
            return RedirectToLocal(returnUrl);
        }

        // If we got this far, something failed, redisplay form
        ModelState.AddModelError("", "The user name or password provided is incorrect.");
        return View(model);
    }
    private ActionResult RedirectToLocal(string returnUrl)
    {
        if (Url.IsLocalUrl(returnUrl))
        {
            return Redirect(returnUrl);
        }
        else
        {
            return RedirectToAction("Index", "Home");
        }
    }

IWebセキュリティ

public interface IWebSecurity
{
    bool login(LoginModel model);
}


public class WebSecurity : IWebSecurity
{
    public bool login(LoginModel model)
    {
        return WebMatrix.WebData.WebSecurity.Login(model.UserName, model.Password, model.RememberMe);
    }
}

MyTestClass

[AfterScenario]
    public void OnAfterScenario() {
        mockRepository.VerifyAll();
    }

    LoginModel loginModel;
    AccountController _controller;

    #region Initializing Mock Repository

    readonly Mock<IWebSecurity> mockRepository = new Mock<IWebSecurity>(MockBehavior.Loose);
    ViewResult viewResult;

    #endregion

    [Given]
    public void Given_Account_controller()
    {
        _controller = new AccountController(mockRepository.Object);
    }

    [When]
    public void When_login_is_called_with_LoginModel(Table table)
    {
         loginModel = new LoginModel
            {
                UserName = table.Rows[0][1],
                Password = table.Rows[1][1]
            };
         mockRepository.Setup(x => x.login(loginModel)).Returns(true);
         viewResult = (ViewResult)_controller.Login(loginModel, "/");
    }

    [Then]
    public void Then_it_should_validate_LoginModel()
    {
       Assert.IsTrue(_controller.ModelState.IsValid);
    }

    [Then]
    public void Then_it_should_return_default_view()
    {
        Assert.AreEqual(viewResult.ViewName, "Index");
    }

Url.IsLocalしかし、私のテストは失敗し、メソッドに来ると期待を与えRedirect to Localます。だから私はここで私の httpcontextbase と httpcontextrequestbase をモックする必要があると思います。

しかし、それをあざける方法がわかりません。

前もって感謝します

4

2 に答える 2

5

をモックする必要がありHttpContextます。この種のことを行うためにこのヘルパーを書きました

public static Mock<HttpContextBase> MockControllerContext(bool authenticated, bool isAjaxRequest)
{
  var request = new Mock<HttpRequestBase>();
  request.SetupGet(r => r.HttpMethod).Returns("GET");
  request.SetupGet(r => r.IsAuthenticated).Returns(authenticated);
  request.SetupGet(r => r.ApplicationPath).Returns("/");
  request.SetupGet(r => r.ServerVariables).Returns((NameValueCollection)null);
  request.SetupGet(r => r.Url).Returns(new Uri("http://localhost/app", UriKind.Absolute));
  if (isAjaxRequest)
    request.SetupGet(x => x.Headers).Returns(new System.Net.WebHeaderCollection { { "X-Requested-With", "XMLHttpRequest" } });

  var server = new Mock<HttpServerUtilityBase>();
  server.Setup(x => x.MapPath(It.IsAny<string>())).Returns(BasePath);

  var response = new Mock<HttpResponseBase>();
  response.Setup(r => r.ApplyAppPathModifier(It.IsAny<string>())).Returns((String url) => url);

  var session = new MockHttpSession();

  var mockHttpContext = new Mock<HttpContextBase>();
  mockHttpContext.Setup(c => c.Request).Returns(request.Object);
  mockHttpContext.Setup(c => c.Response).Returns(response.Object);
  mockHttpContext.Setup(c => c.Server).Returns(server.Object);
  mockHttpContext.Setup(x => x.Session).Returns(session);

  return mockHttpContext;
}

public class MockHttpSession : HttpSessionStateBase
{
  private readonly Dictionary<string, object> sessionStorage = new Dictionary<string, object>();

  public override object this[string name]
  {
    get { return sessionStorage.ContainsKey(name) ? sessionStorage[name] : null; }
    set { sessionStorage[name] = value; }
  }

  public override void Remove(string name)
  {
    sessionStorage.Remove(name);
  }
}

テストメソッドでは、そのように使用します

private AccountController GetController(bool authenticated)
{
  var requestContext = new RequestContext(Evoltel.BeniRosa.Web.Frontend.Tests.Utilities.MockControllerContext(authenticated, false).Object, new RouteData());
  var controller = new CofaniController(cofaniRepository.Object, categorieRepository.Object, emailService.Object, usersService.Object)
  {
    Url = new UrlHelper(requestContext)
  };
  controller.ControllerContext = new ControllerContext()
  {
    Controller = controller,
    RequestContext = requestContext
  };
  return controller;
}

[Test]
public void LogOn_Post_ReturnsRedirectOnSuccess_WithoutReturnUrl()
{
  AccountController controller = GetController(false);
  var httpContext = Utilities.MockControllerContext(false, false).Object;
  controller.ControllerContext = new ControllerContext(httpContext, new RouteData(), controller);
  LogOnModel model = new LogOnModel()
  {
    UserName = "someUser",
    Password = "goodPassword",
    RememberMe = false
  };
  ActionResult result = controller.LogOn(model, null);
  Assert.IsInstanceOf(typeof(RedirectToRouteResult), result);
  RedirectToRouteResult redirectResult = (RedirectToRouteResult)result;
  Assert.AreEqual("Home", redirectResult.RouteValues["controller"]);
  Assert.AreEqual("Index", redirectResult.RouteValues["action"]);
}

それが役に立てば幸い

于 2013-06-17T06:58:58.800 に答える
3

Urlこの特定の問題では、コントローラーのプロパティをモックUrlHelperクラスで単純に上書きできます。

モックの場合は、コントローラーHttpContextに注入HttpContextBaseし、適切なコンテナーを提供するように DI コンテナーを構成するとよいでしょう。後でテスト目的で簡単にモックできます。Autofac には、.NET などの ASP.NET 関連のクラスのコンテナーを自動的に構成する方法があると思いますHttpContextBase

編集

UrlHelper@lazyberezovskyが書いたように、Moqでモックできないようです-インターフェースと仮想メソッドのみをモックできます。しかし、独自のモック オブジェクトを作成することを妨げるものではありません。コンストラクターで必要なため、 mock が必要HttpContextですUrlHelper(実際には、コンストラクターで必要なRequestContextコンストラクターで必要ですUrlHelper)...さらに、IsLocalUrlコンテキストから何も使用しないため、追加のセットアップを提供する必要はありません。

サンプル コードは次のようになります。

コントローラー

public ActionResult Foo(string url)
{
    if (Url.IsLocalUrl(url))
    {
        return Redirect(url);
    }

    return RedirectToAction("Index", "Home");
}

テスト:

[TestClass]
public class HomeControllerTests
{
    private Mock<HttpContextBase> _contextMock;
    private UrlHelper _urlHelperMock;

    public HomeControllerTests()
    {
        _contextMock = new Mock<HttpContextBase>();

        _urlHelperMock = new UrlHelper(new RequestContext(_contextMock.Object, new RouteData()));
    }


    [TestMethod]
    public void LocalUrlTest()
    {
        HomeController controller = new HomeController();
        controller.Url = _urlHelperMock;

        RedirectResult result = (RedirectResult)controller.Foo("/");
        Assert.AreEqual("/", result.Url);
    }

    [TestMethod]
    public void ExternalUrlTest()
    {
        HomeController controller = new HomeController();
        controller.Url = _urlHelperMock;

        RedirectToRouteResult result = (RedirectToRouteResult)controller.Foo("http://test.com/SomeUrl");
        Assert.AreEqual("Index", result.RouteValues["action"]);
        Assert.AreEqual("Home", result.RouteValues["controller"]);
    }
}
于 2013-06-17T07:12:23.617 に答える