我的控制器中有以下行:
string lTempPath = Path.Combine(Server.MapPath("~/Temp"), lRandomFileName);
问题是服务器不是虚拟的,只能使用getter访问。
我得到了
“方法或操作未实施。”
如何模拟此服务器?
我创建的测试如下:
[TestCase]
public void PreviewActionShouldGenerateUrlOfPdf()
{
//Arrange
var server = MockRepository.GenerateMock<HttpServerUtilityBase>();
server.Stub(s => s.MapPath("~Temp")).Return("~/Temp");
var httpContext = MockRepository.GenerateMock<HttpContextBase>();
httpContext.Stub(hc => hc.Server).Return(server);
httpContext.Server.Stub(s => s.MapPath("~/Temp")).Return("~/Temp");
var controller = new StudiesController()
{
ReportingService = MockRepository.GenerateMock<IReportingService>(),
SecurityService = MockRepository.GenerateMock<ISecurityService>()
};
controller.ControllerContext = new ControllerContext(httpContext, new RouteData(), controller);
controller.ReportingService.Stub(rs => rs.GetStudyByGID(new Guid())).Return(new Study());
controller.ReportingService.Stub(rs => rs.ListPractices()).Return(new[] { new Practice(), new Practice() });
controller.SecurityService.Stub(ss => ss.GetUser("")).IgnoreArguments().Return(new User());
controller.ControllerContext.HttpContext = MockRepository.GeneratePartialMock<FakeHttpContext>("http://test.com");
controller.HttpContext.User = new FakePrincipal(new FakeIdentity("test"), new string[0]);
controller.ControllerContext.HttpContext.Stub(x => x.Request).Return(MockRepository.GenerateMock<HttpRequestBase>());
controller.ControllerContext.HttpContext.Request.Stub(x => x.Url).Return(new Uri("http://test.com"));
controller.ReportingService.Stub(
rs =>
rs.GenerateReport(new Study(), new Practice(), new User(), false, ReportGenerationOutputFormat.PDF)).IgnoreArguments().Return(new StudyReportSnapshot());
var content = new ContentResult();
//Act
var result = (ContentResult)controller.Preview(new Guid());
//Assert
Assert.AreEqual(result.Content, content.Content);
}
答案 0 :(得分:13)
您可以在单元测试代码中使用Mocking框架,例如Rhino.Mocks,Moq或FakeItEasy
示例单元测试主体将是(此示例使用Moq)
var homeController = new HomeController();
//create mock of HttpServerUtilityBase
var server = new Mock<HttpServerUtilityBase>();
//set up mock to return known value on call.
server.Setup(x => x.MapPath("~/Temp")).Returns("c:\\temp\\");
var httpContext = new Mock<HttpContextBase>();
httpContext.Setup(x => x.Server).Returns(server.Object);
homeController.ControllerContext = new ControllerContext(httpContext.Object, new RouteData(), homeController);
YourModelName yourModelName = new YourModelName();
yourModelName.lRandomFileName = "zzzz.so";
var result = homeController.YourActionName(yourModelName);
然后你可以断言结果。
希望能给你一些想法
答案 1 :(得分:8)
假设您正在使用某种IOC / DI容器,则不应依赖Controller.Server
。相反,您应该使用HttpServerUtilityBase
。
此示例假定Ninject为IOC容器,但任何常用容器都将执行:
首先,将HttpServerUtilityBase
注册到您的IOC容器中,如下所示:
kernel.Bind<HttpServerUtilityBase>().ToMethod(c => new HttpServerUtilityWrapper(HttpContext.Current.Server));
这将确保您的应用在运行时将使用当前请求的服务器属性。
然后,向您的控制器添加一个构造函数,该构造函数接受HttpServerUtilityBase
:
public MyController(HttpServerUtilityBase server)
{
this._server = server;
}
现在,在您拨打Server.MapPath
之前的任何地方,只需拨打_server.MapPath
即可。
最后,在你的测试中,你可以像这样模拟HttpServerUtilityBase(假设Moq是模拟框架):
var server = new Mock<HttpServerUtilityBase>();
server.Setup(s => s.MapPath(It.IsAny<string>())).Returns<string>(s => /* set up how you want MapPath to behave here */);
既然你提到你没有使用DI框架,你可以诉诸“穷人的依赖注入”。基本上添加一个重载的构造函数:
public MyController()
: this(new HttpServerUtilityWrapper(HttpContext.Current.Server))
{
}
public MyController(HttpServerUtilityBase server)
{
this._server = server;
}
这将允许生产代码使用当前的Web请求,但您可以创建自己的HttpServerUtilityBase
实现来用于测试。