我试图写一个单元测试,但我的测试调用的方法,调用另一个方法,使用UrlHelper
类生成一个URL。调用urlHelper.Action
的结果一直返回null
。
我试过模拟(使用Moq)所有的组件,我认为这个控制器将需要能够得到这个工作,但我仍然得到null
。
单元测试类
[TestFixtureSetUp]
public void Configure_Defaults()
{
var mockHttpContextBase = new Mock<HttpContextBase>();
var mockRequest = new Mock<HttpRequestBase>();
var mockControllerContext = new Mock<ControllerContext>();
var mockWebRoutingRequestContrext = new Mock<RequestContext>();
mockRequest
.Setup(request => request.Url)
.Returns(new Uri("http://dev.fleepos.local/Register"));
mockHttpContextBase
.Setup(httpContext => httpContext.Request)
.Returns(mockRequest.Object);
mockWebRoutingRequestContrext
.Setup(request => request.HttpContext)
.Returns(mockHttpContextBase.Object);
mockWebRoutingRequestContrext
.Setup(request => request.RouteData)
.Returns(new RouteData());
var urlHelper = new UrlHelper(mockWebRoutingRequestContrext.Object);
mockControllerContext
.Setup(controllerContext => controllerContext.HttpContext)
.Returns(mockHttpContextBase.Object);
_registerController = new RegisterController() {ControllerContext = mockControllerContext.Object, Url = urlHelper};
}
[Test]
public void Display_Validate_Account_Page_On_Successful_Registration()
{
//act
var result = (RedirectToRouteResult)_registerController.Register(_userRegisterationViewModel);
//assert
Assert.That(result.RouteValues["action"], Is.EqualTo("ValidateAccount"));
}
控制器动作调用的控制器方法
private string GenerateActionLink(string actionName, string token, string username)
{
string validationLink = null;
if (Request.Url != null)
{
var urlHelper = new UrlHelper(ControllerContext.RequestContext);
validationLink = urlHelper.Action(actionName, "Register",
new { Token = token, Username = username },
Request.Url.Scheme);
}
return validationLink;
}
控制器已经有一个UrlHelper Url
属性,可以模拟做你想做的事情。通过在控制器操作调用的控制器方法中创建new UrlHelper
,就失去了替换mock/fake的机会。
首先更新控制器操作调用的控制器方法,使其测试友好
private string GenerateActionLink(string actionName, string token, string username) {
string validationLink = null;
if (Request.Url != null) {
validationLink = Url.Action(actionName, "Register",
new { Token = token, Username = username },
Request.Url.Scheme);
}
return validationLink;
}
现在有更多的控制控制器的UrlHelper。UrlHelper也可以被模拟并传递给控制器上下文
这是上面解释的一个最小的完整示例。
[TestClass]
public class UrlHelperTest {
[TestMethod]
public void MockUrlHelper() {
//Arrange
var requestUrl = new Uri("http://myrequesturl");
var request = Mock.Of<HttpRequestBase>();
var requestMock = Mock.Get(request);
requestMock.Setup(m => m.Url).Returns(requestUrl);
var httpcontext = Mock.Of<HttpContextBase>();
var httpcontextSetup = Mock.Get(httpcontext);
httpcontextSetup.Setup(m => m.Request).Returns(request);
var actionName = "MyTargetActionName";
var expectedUrl = "http://myfakeactionurl.com";
var mockUrlHelper = new Mock<UrlHelper>();
mockUrlHelper
.Setup(m => m.Action(actionName, "Register", It.IsAny<object>(), It.IsAny<string>()))
.Returns(expectedUrl)
.Verifiable();
var sut = new MyController();
sut.Url = mockUrlHelper.Object;
sut.ControllerContext = new ControllerContext {
Controller = sut,
HttpContext = httpcontext,
};
//Act
var result = sut.MyAction();
//Assert
mockUrlHelper.Verify();
}
public class MyController : Controller {
[HttpPost]
public ActionResult MyAction() {
var link = GenerateActionLink("MyTargetActionName", string.Empty, string.Empty);
return View((object)link);
}
private string GenerateActionLink(string actionName, string token, string username) {
string validationLink = null;
if (Request.Url != null) {
var encodedToken = EncodedUrlParameter(token);
var url = Url.Action(actionName, "Register", new { Token = encodedToken, Username = username }, Request.Url.Scheme);
validationLink = url;
}
return validationLink;
}
private string EncodedUrlParameter(string token) {
return "Fake encoding";
}
}
}