2017-08-24 75 views
1

我使用Asp.netCore和下面的代碼是我的行動的一部分,我需要測試XUnit。問題是URL這是null,而我正在測試的行動方法。我如何模擬URL及其功能RoutUrl返回我期望的URLMocking Url.RouteUrl

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("[email protected]"); 

    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) 

回答

2

特定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

最終包裝到another extension method創建UrlRouteContext

由於起訂量不能嘲笑擴展方法,即類是你需要模擬,使擴展方法流程完成什麼

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