如何避免出于单元测试目的的HttpContext.Server.MapPath [英] How to avoid HttpContext.Server.MapPath for Unit Testing Purposes
问题描述
我正在ASP.net MVC 5应用程序中工作.我想对控制器的操作进行单元测试,如下所示:
I am working in an ASP.net MVC 5 application. I would like to Unit Test my controller action which looks like this
public ActionResult Search()
{
var vm = SetupSearchViewModel();
return View(vm);
}
所有艰苦的工作都由SetupSearchViewModel()
方法完成,该方法本身就是一个协调器,调用了许多其他方法,其中一个就是
All the hard work is done by the SetupSearchViewModel()
method, which itself is an orchestrator calling many different other methods, one of which is this
private string ExtractJsonFile(string filename)
{
var filePath = HttpContext.Server.MapPath(filename);
var json = System.IO.File.ReadAllText(filePath);
return json;
}
我计划对此特定动作进行许多单元测试,但是我从一个非常简单的单元测试开始,该单元测试用于检查是否返回了正确类型的ActionResult.
I plan on doing many Unit Tests on this particular action, but I'm starting with a very simple Unit Test which checks that the correct type of ActionResult is returned
[Test]
public void Search_Get_ReturnsViewResult()
{
// arrange
var performanceController = PerformanceControllerInstance;
// act
var result = performanceController.Search();
//assert
Assert.IsNotNull(result as ViewResult);
}
由于ExtractJsonFile
方法,测试失败.它使用HttpContext
,即null
.我正在使用Rhino Mocks来模拟各种类.
The test is failing because of the ExtractJsonFile
method. It uses HttpContext
and that is null
. I am using Rhino Mocks to do the mocking of the various classes.
对此进行单元测试的最佳方法是什么?达林在此线程中建议,如果我们希望我们避免使用HttpContext.Current
代码单元测试.
What would be the best way to Unit Test this? Darin in this thread suggest we avoid HttpContext.Current
if we want our code Unit Tested.
通过尝试模拟HttpContext并将其设置为非null的方式,但是Server
是null
,我也可以继续模拟我所想的(我还不知道如何),但是有没有更好的办法?如有需要,我可以进行重大重构.
By the way I tried mocking the HttpContext and made it not null, but then the Server
is null
, I can go ahead and mock that too I suppose (I don't know how yet), but is there no better way? I've no problem doing major refactoring if needed.
推荐答案
HttpContext.Server.MapPath
将需要基础虚拟目录提供程序,该虚拟目录提供程序在单元测试期间不存在.在可以模拟以使代码可测试的服务后面抽象路径映射.
HttpContext.Server.MapPath
would require an underlying virtual directory provider which would not exist during the unit test. Abstract the path mapping behind a service that you can mock to make the code testable.
public interface IPathProvider {
string MapPath(string path);
}
在具体服务的实现中,您可以调用以映射路径并检索文件.
In the implementation of the concrete service you can make your call to map the path and retrieve the file.
public class ServerPathProvider: IPathProvider {
public string MapPath(string path) {
return HttpContext.Current.Server.MapPath(path);
}
}
您将把抽象注入到您的控制器中或在需要和使用的地方
you would inject the abstraction into your controller or where needed and used
public MyController : Controller {
public MyController(IPathProvider pathProvider) {
this.pathProvider = pathProvider;
}
//...other code removed for brevity
private string ExtractJsonFile(string filename) {
var filePath = pathProvider.MapPath(filename);
var json = System.IO.File.ReadAllText(filePath);
return json;
}
}
使用您选择的模拟框架,然后可以模拟提供程序
Using your mocking framework of choice you can then mock the provider
[Test]
public void Search_Get_ReturnsViewResult() {
// arrange
IPathProvider mockedPathProvider = //...insert your mock/fake/stub here
var performanceController = PerformanceControllerInstance(mockedPathProvider);
// act
var result = performanceController.Search();
//assert
Assert.IsNotNull(result as ViewResult);
}
并且不与HttpContext
您甚至可以更进一步,将整个ExtractJsonFile(string filename)
重构为自己的服务,以解决与磁盘相关的问题.
You could even go further and refactor the entire ExtractJsonFile(string filename)
into its own service to get around being tied to disk as well.
public interface IJsonProvider {
string ExtractJsonFile(string filename);
}
此服务现在足够灵活,可以根据需要从其他来源(如Web服务)获取文件.
This service is now flexible enough to get the file from other sources like web service if needed.
这篇关于如何避免出于单元测试目的的HttpContext.Server.MapPath的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!