9

我的控制器中有以下行:

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

    }
4

2 回答 2

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

然后你可以断言结果。

希望能给你一些想法

于 2013-06-27T00:28:48.030 回答
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以用于测试。

于 2013-06-27T00:30:22.863 回答