嘲笑Url.RouteUrl

时间:2017-08-24 07:55:55

标签: c# unit-testing asp.net-core-mvc moq xunit

我使用Asp.netCore,以下代码是我需要通过XUnit进行测试的操作的一部分。问题是URL在我测试操作方法时为空。如何模拟URL及其函数RoutUrl以返回我期望的URL

var callbackUrl = Url.RouteUrl("ConfirmEmail", new { userId = user.Id, token }, Request.Scheme);

我也试过这段代码,但根本不起作用。

string locationUrl = "http://location/";
var mockUrlHelper = new Mock<IUrlHelper>();
mockUrlHelper
    .Setup(x => x.RoutUrl("ConfirmEmail", It.IsAny<object>(), It.IsAny<string>()))
    .Returns(locationUrl);

_accountController.Url = mockUrlHelper.Object;

这是我正在测试的行动方法:

[HttpPost]
public async Task<JsonResult> SendEmailConfirmation(string email)
{
    if (string.IsNullOrEmpty(email)) throw new Exception("Inavlid parameter");

    var user = await _userManager.GetUserAsync(User);

    if (user.Email.ToLower() == email.ToLower().Trim())
        return Json(false);

    user.EmailConfirmed = false;
    user.Email = email;
    await _userManager.UpdateAsync(user);

    var token = await _userManager.GenerateChangeEmailTokenAsync(user, email);
    var callbackUrl = Url.RouteUrl("ConfirmEmail", new { userId = user.Id, token }, Request.Scheme);
    await _emailService.SendEmailConfirmationUserAsync(user.Email, user.FirstName, callbackUrl);

    return Json(true);
}

这是我的测试:

[Fact]
public async Task SendEmailConfirmation_NewEmail_ShouldReturnTrue()
{
    const string token = "TokenString";
    var applicationUser = StubFactory.GetUser();

    _userManagerMock
        .Setup(x => x.GetUserAsync(It.IsAny<ClaimsPrincipal>()))
        .ReturnsAsync(applicationUser);

    _userManagerMock
        .Setup(x => x.UpdateAsync(applicationUser))
        .ReturnsAsync(IdentityResult.Success);

    _userManagerMock
        .Setup(x => x.GenerateChangeEmailTokenAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>()))
        .ReturnsAsync(token);

    _emailServiceMock
        .Setup(x => x.SendEmailConfirmationUserAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
        .ReturnsAsync(It.IsAny<EmailResult>());

    //ToDO  Mock Url.RoutUrl 

    string locationUrl = "http://location/";
    var mockUrlHelper = new Mock<IUrlHelper>();
    mockUrlHelper
        .Setup(x => x.RouteUrl("ConfirmEmail", It.IsAny<object>(), It.IsAny<string>()))
        .Returns(locationUrl);

    _accountController.Url = mockUrlHelper.Object;


    var result = await _accountController.SendEmailConfirmation("newemail@something.com");

    result.Value.ShouldBe(true);
    _userManagerMock.Verify(x => x.GetUserAsync(It.IsAny<ClaimsPrincipal>()), Times.Once);
    _userManagerMock.Verify(x => x.GenerateChangeEmailTokenAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>()), Times.Once);
    _emailServiceMock.Verify(x => x.SendEmailConfirmationUserAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()), Times.Once);
}  

我在单元测试会话中收到的错误消息:

System.ArgumentNullException
Value cannot be null.
Parameter name: helper
at Microsoft.AspNetCore.Mvc.UrlHelperExtensions.RouteUrl(IUrlHelper helper, 
String routeName, Object values, String protocol)

1 个答案:

答案 0 :(得分:3)

您正在嘲笑的特定RouteUrl方法是一种扩展方法

/// <summary>
/// Generates a URL with an absolute path for the specified route <paramref name="routeName"/> and route
/// <paramref name="values"/>, which contains the specified <paramref name="protocol"/> to use.
/// </summary>
/// <param name="helper">The <see cref="IUrlHelper"/>.</param>
/// <param name="routeName">The name of the route that is used to generate URL.</param>
/// <param name="values">An object that contains route values.</param>
/// <param name="protocol">The protocol for the URL, such as "http" or "https".</param>
/// <returns>The generated URL.</returns>
public static string RouteUrl(
    this IUrlHelper helper,
    string routeName,
    object values,
    string protocol)
{
    if (helper == null)
    {
        throw new ArgumentNullException(nameof(helper));
    }

    return helper.RouteUrl(routeName, values, protocol, host: null, fragment: null);
}

来源:UrlHelperExtensions.cs

最终包含到创建UrlRouteContext的{​​{3}}。

由于Moq无法模拟扩展方法,因此您需要模拟该类以使扩展方法流程完成

string locationUrl = "http://location/";
var mockUrlHelper = new Mock<IUrlHelper>();
mockUrlHelper
    .Setup(x => x.RouteUrl(It.IsAny<UrlRouteContext>()))
    .Returns(locationUrl);