我对我的家庭控制器进行单元测试。此测试工作正常,直到我添加了一个保存图像的新功能。
引起问题的方法如下所示。
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);
}
}
}
由于调用来自单元测试,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)));
}
答案 0 :(得分:12)
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);
}
}
}
您看,现在这种方法不再依赖于任何Web上下文,可以单独测试。调用者有责任传递正确的路径。
答案 1 :(得分: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("/",@"\"));
//...
执行此操作,mock将简单地用〜:/ testserverdir \ function替换〜/
希望它有所帮助!
答案 2 :(得分:2)
有时候只是模拟对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(&#34;〜&#34;)。
答案 3 :(得分:0)
以下为我工作。
string pathToTestScripts = @"..\..\..\RelatavePathToTestScripts\";
string testScriptsFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, pathToTestScripts);
var server = new Mock<HttpServerUtilityBase>(); // Need to mock Server.MapPath() and give location of random.ps1
server.Setup(x => x.MapPath(PowershellScripts.RANDOM_PATH)).Returns(testScriptsFolder + "random.ps1");
var request = new Mock<HttpRequestBase>(); // To mock a query param of s=1 (which will make random.ps1 run for 1 second)
request.Setup(x => x.QueryString).Returns(new System.Collections.Specialized.NameValueCollection { { "s", "1" } });
var httpContext = new Mock<HttpContextBase>();
httpContext.Setup(x => x.Server).Returns(server.Object);
httpContext.Setup(x => x.Request).Returns(request.Object);
YourController controller = new YourController();
controller.ControllerContext = new ControllerContext(httpContext.Object, new RouteData(), controller);