1

A few of my controller actions call this method GenerateActionLink.

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

This is to generate a validation link which will be sent via email. It works perfectly. The issue I'm having is when testing a controller action which called the method. Url is null.

How can i mock that and use the mock in my unit test ?

I am using Moq and NUnit.

NOTE: I need to be able to pass in an actionName, this is why i am not concatinating Request.Url with my parameter values because Request.Url will always have the action the request comes from which is generally not the action i want in the link, this is why i am using Url.Action to generate an action link.

1
  • Mock UrlHelper and set the controller's Url property when arranging the test. To mock the request mock the controller's http context and set the controller context. Commented Oct 30, 2016 at 22:04

2 Answers 2

1

Mock UrlHelper and set the controller's Url property when arranging the test. To mock the request mock the controller's http context and set the controller context.

To demonstrate here is a sample controller based on the provided example above.

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

}

Here is a unit test example that mocks up all the necessary framework dependencies

[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();
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

This fixed my problem. Thanks.
0

So this is my current solution, I ended up constructing the link manually. If there are any better solution please do let me know.

    private string GenerateActionLink(string actionName, string token, string username)
    {
        string validationLink = null;
        if (Request.Url != null)
        {
            var encodedToken = EncodedUrlParameter(token);
            var encodedEmail = EncodedUrlParameter(username);
            var concatenatedUrl =
                $"{Request.Url.Scheme}://{Request.Url.Host}/Register/{actionName}?Token={encodedToken}&Username={encodedEmail}"; 
            validationLink = concatenatedUrl;
        }

        return validationLink;
    }

This way i can still pass in an actionName. If I use the Request.Url, this will always have an action which is usually not what i want to use as stated in my question.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.