Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock context while unit testing code using VirtualPathUtility.GetAbsolute method

I am running unit tests on code which uses VirtualParthUtility.GetAbsolute, but am having problems mocking the context for this to work.

I've set up a mock context with Moq as follows

    private Mock<HttpContextBase> MakeMockHttpContext(string url) // url = "~/"
    {
        var mockHttpContext = new Mock<HttpContextBase>();

        // Mock the request
        var mockRequest = new Mock<HttpRequestBase>();
        mockRequest.Setup(x => x.ApplicationPath).Returns("/");
        mockRequest.Setup(x => x.Path).Returns("/");
        mockRequest.Setup(x => x.PathInfo).Returns(string.Empty);
        mockRequest.Setup(x => x.AppRelativeCurrentExecutionFilePath).Returns(url);

        mockHttpContext.Setup(x => x.Request).Returns(mockRequest.Object);

        // Mock the response
        var mockResponse = new Mock<HttpResponseBase>();
        mockResponse.Setup(x => x.ApplyAppPathModifier(It.IsAny<string>())).Returns((string s) => s);

        mockHttpContext.Setup(x => x.Response).Returns(mockResponse.Object);

        return mockHttpContext;
    }

And attached this to an MVC Controller

_myController.ControllerContext = new ControllerContext(MakeMockHttpContext("~/").Object, new RouteData(), _slideSelectorController);

The code that runs during the test hits the line:

venue.StyleSheetUrl = VirtualPathUtility.ToAbsolute(venue.StyleSheetUrl); // input like "~/styles/screen.css"

Every time this runs, it steps into System.Web.VirtualPathUtility, with the problem that the "VirtualParthString" to be returned always throws an exception:

 public static string ToAbsolute(string virtualPath)
{
  return VirtualPath.CreateNonRelative(virtualPath).VirtualPathString;
}

The reason for the exception is easy to see in System.Web.VirtualPathString:

    public string VirtualPathString
{
  get
  {
    if (this._virtualPath == null)
    {
      if (HttpRuntime.AppDomainAppVirtualPathObject == null)
      {
        throw new HttpException(System.Web.SR.GetString("VirtualPath_CantMakeAppAbsolute", new object[] { this._appRelativeVirtualPath }));
      }
      if (this._appRelativeVirtualPath.Length == 1)
      {
        this._virtualPath = HttpRuntime.AppDomainAppVirtualPath;
      }
      else
      {
        this._virtualPath = HttpRuntime.AppDomainAppVirtualPathString + this._appRelativeVirtualPath.Substring(2);
      }
    }
    return this._virtualPath;
  }
}

Through the Watch Window I can see that _virtualPath and HttpRuntime.AppDomainAppVirtualPathString are both null, hence it throws an exception.

If _virtualPath were set, the exception wouldn't happen. But after the VirtualPath.Create method has created a new VirtualPath object, it doesn't set the _virtualPath property before it is returned. An extract from the Create method up to this point is:

VirtualPath path = new VirtualPath();
  if (UrlPath.IsAppRelativePath(virtualPath))
  {
    virtualPath = UrlPath.ReduceVirtualPath(virtualPath);
    if (virtualPath[0] == '~')
    {
      if ((options & VirtualPathOptions.AllowAppRelativePath) == 0)
      {
        throw new ArgumentException(System.Web.SR.GetString("VirtualPath_AllowAppRelativePath", new object[] { virtualPath }));
      }
      path._appRelativeVirtualPath = virtualPath;
      return path;

So if anyone can suggest how to get this unit test working, that will be very helpful!

Thanks,

Steve

like image 918
Appetere Avatar asked Sep 24 '11 12:09

Appetere


People also ask

Which objects or methods do you mock in a unit test?

Mocking for unit testing is when you create an object that implements the behavior of a real subsystem in controlled ways. In short, mocks are used as a replacement for a dependency.

Is mocking necessary in unit testing?

They are so much preferred because they enable you to write unit tests easily and provide an environment with good unit testing practices. Mocks have a crucial difference from other test doubles.

What does mocking mean in unit testing?

Mocking means creating a fake version of an external or internal service that can stand in for the real one, helping your tests run more quickly and more reliably.


1 Answers

I would just create a wrapper interface. Something like:

public interface IPathUtilities
{
    string ToAbsolute(string virtualPath);
}

You can inject that into your controller. At test time, use a stub. At runtime, you'll have a class that implements IPathUtilities and calls VirtualPathUtility.ToAbsolute().

like image 135
PatrickSteele Avatar answered Nov 03 '22 23:11

PatrickSteele