MVC模拟(Moq)

编程入门 行业动态 更新时间:2024-10-23 11:23:48
本文介绍了MVC模拟(Moq)-HttpContext.Current.Server.MapPath的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我有一种方法正在尝试进行单元测试,该方法使用 HttpContext.Current.Server.MapPath 以及 File.ReadAllLines 如下:

I have a method I am attempting to Unit Test which makes use of HttpContext.Current.Server.MapPath as well as File.ReadAllLines as follows:

public List<ProductItem> GetAllProductsFromCSV() { var productFilePath = HttpContext.Current.Server.MapPath(@"~/CSV/products.csv"); String[] csvData = File.ReadAllLines(productFilePath); List<ProductItem> result = new List<ProductItem>(); foreach (string csvrow in csvData) { var fields = csvrow.Split(','); ProductItem prod = new ProductItem() { ID = Convert.ToInt32(fields[0]), Description = fields[1], Item = fields[2][0], Price = Convert.ToDecimal(fields[3]), ImagePath = fields[4], Barcode = fields[5] }; result.Add(prod); } return result; }

我有一个单元测试设置,该设置(如预期的那样)失败:

I have a Unit Test setup which (as expected) fails:

[TestMethod()] public void ProductCSVfileReturnsResult() { ProductsCSV productCSV = new ProductsCSV(); List<ProductItem> result = productCSV.GetAllProductsFromCSV(); Assert.IsNotNull(result); }

此后,我对Moq和依赖注入进行了很多阅读,但我似乎无法实现.我还在SO上看到了一些方便的答案,例如:如何避免出于单元测试目的而使用HttpContext.Server.MapPath ,但是对于我的实际示例,我只是无法遵循它.

I have since done a lot of reading on Moq and Dependancy Injection which I just dont seem to be able to implement. I have also seen a few handy answers on SO such as: How to avoid HttpContext.Server.MapPath for Unit Testing Purposes however I am just unable to follow it for my actual example.

我希望有人能够看一下这个问题,并确切地告诉我如何进行此方法的成功测试.我觉得我有很多背景知识,但无法将所有背景知识融为一体.

I am hoping someone is able to take a look at this and tell me exactly how I might go about implementing a successful test for this method. I feel I have a lot of the background required but am unable to pull it all together.

推荐答案

在当前形式下,所讨论的方法与实现问题紧密相关,而在进行隔离测试时,这些问题很难复制.

In its current form, the method in question is too tightly coupled to implementation concerns that are difficult to replicate when testing in isolation.

以您的示例为例,我建议将所有这些实现关注点抽象到其自己的服务中.

For your example, I would advise abstracting all those implementation concerns out into its own service.

public interface IProductsCsvReader { public string[] ReadAllLines(string virtualPath); }

并明确地将其作为依赖项注入到相关的类中

And explicitly inject that as a dependency into the class in question

public class ProductsCSV { private readonly IProductsCsvReader reader; public ProductsCSV(IProductsCsvReader reader) { this.reader = reader; } public List<ProductItem> GetAllProductsFromCSV() { var productFilePath = @"~/CSV/products.csv"; var csvData = reader.ReadAllLines(productFilePath); var result = parseProducts(csvData); return result; } //This method could also eventually be extracted out into its own service private List<ProductItem> parseProducts(String[] csvData) { List<ProductItem> result = new List<ProductItem>(); //The following parsing can be improved via a proper //3rd party csv library but that is out of scope //for this question. foreach (string csvrow in csvData) { var fields = csvrow.Split(','); ProductItem prod = new ProductItem() { ID = Convert.ToInt32(fields[0]), Description = fields[1], Item = fields[2][0], Price = Convert.ToDecimal(fields[3]), ImagePath = fields[4], Barcode = fields[5] }; result.Add(prod); } return result; } }

请注意,该类现在如何与在何处或如何获取数据无关.仅当它被询问时才获取数据.

Note how the class now is not concerned with where or how it gets the data. Only that it gets the data when asked.

这可以进一步简化,但这不在此问题的范围内. (阅读SOLID原理)

This could be simplified even further but that is outside of the scope of this question. (Read up on SOLID principles)

现在,您可以灵活地模拟依赖关系,以进行较高级别的预期行为的测试.

Now you have the flexibility to mock the dependency for testing at a high level, expected behavior.

[TestMethod()] public void ProductCSVfileReturnsResult() { var csvData = new string[] { "1,description1,Item,2.50,SomePath,BARCODE", "2,description2,Item,2.50,SomePath,BARCODE", "3,description3,Item,2.50,SomePath,BARCODE", }; var mock = new Mock<IProductsCsvReader>(); mock.Setup(_ => _.ReadAllLines(It.IsAny<string>())).Returns(csvData); ProductsCSV productCSV = new ProductsCSV(mock.Object); List<ProductItem> result = productCSV.GetAllProductsFromCSV(); Assert.IsNotNull(result); Assert.AreEqual(csvData.Length, result.Count); }

为完整起见,这里是依赖项的生产版本的样子.

For completeness here is what a production version of the dependency could look like.

public class DefaultProductsCsvReader : IProductsCsvReader { public string[] ReadAllLines(string virtualPath) { var productFilePath = HttpContext.Current.Server.MapPath(virtualPath); String[] csvData = File.ReadAllLines(productFilePath); return csvData; } }

使用DI只是确保抽象和实现已在组合根目录下注册.

Using DI just make sure that the abstraction and the implementation are registered with the composition root.

更多推荐

MVC模拟(Moq)

本文发布于:2023-11-09 15:48:29,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1572772.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:MVC   Moq

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!