0

Given an ASP.NET project with some files in the structure that have Content listed as their Build Action, how does one refer to that content in a manner that works both for IIS and Visual Studio's testing suite?

Our old/existing practice is to refer to the files using Server.MapPath():

String filename = HttpContext.Current.Server.MapPath("/common/template_1.txt");

However, this fails during testing. The test runner doesn't have an HttpContext.

Is there a mechanism for referring to /common/template_1.txt that will work with or without the HttpContext? Or do we need to fabricate an HttpContext?


If we need to replicate the Content items to the test, that's OK (though not ideal).

Mikael Engver
  • 4,078
  • 4
  • 40
  • 51
svidgen
  • 13,099
  • 4
  • 31
  • 51
  • http://stackoverflow.com/questions/9624242/setting-the-httpcontext-current-session-in-unit-test – Donal Aug 27 '14 at 19:52
  • @Donal Thanks for the link. We're able to fake the `HttpContext` if absolutely necessarily. But, we're making great strides in abstracting our other `HttpContext` dependencies away. If there's a reasonable way to work around `MapPath()` specifically, that's what I'm looking for. – svidgen Aug 27 '14 at 19:54
  • Testing that involves external sources (db, files...) should be done using mocks or stubs. – walther Aug 27 '14 at 19:55
  • @walther ... that may be a good point. You think we should abstract the `MapPath` call away? And in testing, have it refer to local test versions of the template files? – svidgen Aug 27 '14 at 19:56
  • Yes, exactly. I presume we're talking here about unit testing, right? There are different types of testing and some do involve external sources, but it requires a different approach. – walther Aug 27 '14 at 20:00
  • @walther You'd probably call it integration testing at this point. We're hitting a development database; but we're doing everything in the scope of transactions to avoid making permanent changes. I think your point is on-target either way though. Thanks! – svidgen Aug 27 '14 at 20:03
  • @walther If you get around to putting that in an answer (as a complete thought), I'll give you a juicy green checkmark! ... If not, I'll add the solution myself later. – svidgen Aug 27 '14 at 20:04
  • The namespace System.Web.Abstractions has an abstraction of the HttpServerUtility - HttpServerUtilityBase. You should be able to mock this. – Donal Aug 27 '14 at 20:05
  • Have a look here: http://www.rickardnilsson.net/post/How-to-unit-test-code-which-depends-on-HttpContextCurrentServer – Donal Aug 27 '14 at 20:06
  • 1
    One option is to change the files to embedded resource and grab it that way, you could create a file provider class, create a http implementation and flat file implementation, use something crazy like Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase) instead of map path, so many options.... tempted to close vote due to the broadness of the question. – Mike Miller Aug 27 '14 at 20:25

1 Answers1

0

Your tests are probably in another project than your Web project, so it can be trick to navigate from the test project to a sub directory in the Web Project.

Another solution is to put your call to HttpContext.Current.Server.MapPath outside the class that you calling in your test. And then take the filename (or file content) as an method argument or injected through the class constructor. Then you will be able to send in a fake filename in your test.

If you need to use the file content in your tests, then a good solution can be to duplicate the file as an embedded resource as suggested by @MikeMiller and then you can read it by the following code:

private string GetEmbeddedFileResource()
{
    var assembly = Assembly.GetExecutingAssembly();
    const string resourceName = "TestProjectNamespace.TestFileFolder.template_1.txt";

    var stream = assembly.GetManifestResourceStream(resourceName);
    if (stream == null) return string.Empty;
    using (var reader = new StreamReader(stream))
    {
        var result = reader.ReadToEnd();
        return result;
    }
}
Mikael Engver
  • 4,078
  • 4
  • 40
  • 51