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");
        }
    }

网络安全

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);
    }
}

我的测试类

[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.IsLocalRedirect 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 有一些自动的方法来为 ASP.NET 相关的类(如HttpContextBase.

编辑

正如@lazyberezovsky 所写的那样,您似乎无法UrlHelper使用 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 回答