Mock HttpContext.Current.Server.MapPath с использованием Moq?
im unit тестирует мой домашний контроллер. Этот тест работал нормально, пока я не добавил новую функцию, которая сохраняет изображения.
Ниже приведен метод, вызывающий проблему.
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);
}
}
}
Поскольку вызов происходит от unit test, HttpContext.Current имеет значение null и выдает исключение. Прочитав о Moq и некоторых уроках об использовании Moq с сеансами, я уверен, что это можно сделать.
до сих пор этот код unit test появился, но проблема связана с 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)));
}
Ответы
Ответ 1
HttpContext.Current
- это то, что вы никогда не должны использовать, если вы когда-либо ожидали, что ваш код будет проверен модулем. Это статический метод, который просто возвращает null, если нет веб-контекста, который имеет место в unit test и не может быть издевательством. Таким образом, одним из способов рефакторинга вашего кода будет следующее:
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);
}
}
}
Вы видите, теперь этот метод больше не зависит от какого-либо веб-контекста и может быть протестирован изолированно. Ответчик должен передать правильный путь.
Ответ 2
Я согласен с ответом Дарина, но если вам действительно нужна функция 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("/",@"\"));
//...
Выполняя это, mock просто заменит ~/на c:\testserverdir\function
Надеюсь, что это поможет!
Ответ 3
Иногда бывает полезно просто издеваться над вызовом server.MapPath.
Это решение работает для меня с помощью moq.
Я только высмеиваю базовый путь к приложению.
_contextMock = new Mock<HttpContextBase>();
_contextMock.Setup(x => x.Server.MapPath("~")).Returns(@"c:\yourPath\App");
_controller = new YourController();
_controller.ControllerContext = new ControllerContext(_contextMock.Object, new RouteData(), _controller);
В вашем контроллере теперь вы можете пользователь Server.MapPath( "~" ).