使用Moq模拟HttpContext.Current.Server.MapPath?

JGi*_*tin 11 c# unit-testing moq asp.net-mvc-2

我单位测试我的家庭控制器.此测试工作正常,直到我添加了一个保存图像的新功能.

导致问题的方法如下.

    public static void SaveStarCarCAPImage(int capID)
    {
        byte[] capBinary = Motorpoint2011Data.RetrieveCapImageData(capID);

        if (capBinary != null)
        {
            MemoryStream ioStream = new MemoryStream();
            ioStream = new MemoryStream(capBinary);

            // save the memory stream as an image
            // Read in the data but do not close, before using the stream.

            using (Stream originalBinaryDataStream = ioStream)
            {
                var path = HttpContext.Current.Server.MapPath("/StarVehiclesImages");
                path = System.IO.Path.Combine(path, capID + ".jpg");
                Image image = Image.FromStream(originalBinaryDataStream);
                Image resize = image.GetThumbnailImage(500, 375, null, new IntPtr());
                resize.Save(path, System.Drawing.Imaging.ImageFormat.Jpeg);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

由于调用来自单元测试,HttpContext.Current为null并抛出异常.在阅读了Moq以及关于将Moq与会话一起使用的一些教程之后,我确定它可以完成.

到目前为止,单元测试代码已经提出,但问题是HTTPContext.Current始终为null,仍然抛出异常.

    protected ControllerContext CreateStubControllerContext(Controller controller)
    {
        var httpContextStub = new Mock<HttpContextBase>
        {
            DefaultValue = DefaultValue.Mock
        };

        return new ControllerContext(httpContextStub.Object, new RouteData(), controller);
    }

    [TestMethod]
    public void Index()
    {
        // Arrange
        HomeController controller = new HomeController();            
        controller.SetFakeControllerContext();

        var context = controller.HttpContext;

        Mock.Get(context).Setup(s => s.Server.MapPath("/StarVehiclesImages")).Returns("My Path");

        // Act
        ViewResult result = controller.Index() as ViewResult;

        // Assert
        HomePageModel model = (HomePageModel)result.Model;
        Assert.AreEqual("Welcome to ASP.NET MVC!", model.Message);
        Assert.AreEqual(typeof(List<Vehicle>), model.VehicleMakes.GetType());
        Assert.IsTrue(model.VehicleMakes.Exists(x => x.Make.Trim().Equals("Ford", StringComparison.OrdinalIgnoreCase)));
    }
Run Code Online (Sandbox Code Playgroud)

Dar*_*rov 13

HttpContext.Current如果您希望您的代码经过单元测试,那么您绝对不应该使用它.它是一个静态方法,如果没有Web上下文(单元测试的情况并且无法模拟),它只返回null.因此,重构代码的一种方法如下:

public static void SaveStarCarCAPImage(int capID, string path)
{
    byte[] capBinary = Motorpoint2011Data.RetrieveCapImageData(capID, path);

    if (capBinary != null)
    {
        MemoryStream ioStream = new MemoryStream();
        ioStream = new MemoryStream(capBinary);

        // save the memory stream as an image
        // Read in the data but do not close, before using the stream.

        using (Stream originalBinaryDataStream = ioStream)
        {
            path = System.IO.Path.Combine(path, capID + ".jpg");
            Image image = Image.FromStream(originalBinaryDataStream);
            Image resize = image.GetThumbnailImage(500, 375, null, new IntPtr());
            resize.Save(path, System.Drawing.Imaging.ImageFormat.Jpeg);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您看,现在这种方法不再依赖于任何Web上下文,可以单独测试.调用者有责任传递正确的路径.


小智 9

我同意Darin的答案,但如果你真的需要moq Server.MapPath函数你可以做这样的事情

//...
var serverMock = new Mock<HttpServerUtilityBase>(MockBehavior.Loose);
serverMock.Setup(i => i.MapPath(It.IsAny<String>()))
   .Returns((String a) => a.Replace("~/", @"C:\testserverdir\").Replace("/",@"\"));
//...
Run Code Online (Sandbox Code Playgroud)

执行此操作,mock将简单地用〜:/ testserverdir \函数替换〜/

希望能帮助到你!

  • 我错过了什么吗?我仍然无法模拟HttpContext的那部分因为context.Server没有setter.所以我认为没有办法在HttpContext中实际使用你的HttpServerUtilityBase模拟 (5认同)