我有一个方法(下面),它从MVC应用程序中的控制器调用,然后输出一个excel文件。
方法:
public static void ExportToExcel(IEnumerable<dynamic> data, string bookName, string sheetName)
{
XLWorkbook workbook = new XLWorkbook();
var worksheet = workbook.Worksheets.Add(sheetName);
worksheet.Cell(1, 1).InsertTable(data);
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
HttpContext.Current.Response.AddHeader("content-disposition", String.Format(@"attachment;filename={0}.xlsx", bookName.Replace(" ", "_")));
using (MemoryStream memStream = new MemoryStream())
{
workbook.SaveAs(memStream);
memStream.WriteTo(HttpContext.Current.Response.OutputStream);
memStream.Close();
}
HttpContext.Current.Response.End();
}
控制器:
[ActionName("ExportData")]
public ActionResult ExportData()
{
ExcelExport.ExportToExcel(_dbaccess.GetAllData()), "Workbook", "Worksheet");
return RedirectToAction("Index");
}
我该如何测试这种方法?
答案 0 :(得分:2)
您应该更多地分割方法。创建一个返回byte []的方法,该byte []生成表示文件的字节数组:
public static byte[] ExportToExcel(IEnumerable<dynamic> data, string bookName, string sheetName)
然后创建一个实际保存到磁盘的方法:
public static bool SaveFileToDisk(byte[] file, string path)
然后,您可以测试ExportToExcel
方法断言它返回已知字节[]
答案 1 :(得分:1)
首先,您需要重构该方法,使其更具可测试性。有太多的担忧混在一起使测试变得容易。 (我的意见)。
删除工作簿生成,它可以属于同一个类或某个依赖项
public interface IGetWorkBook {
XLWorkbook GetWorkBook(IEnumerable<dynamic> data, string sheetName);
}
其中的实现看起来与您原始方法中的内容完全相同。
public XLWorkbook GetWorkBook(IEnumerable<dynamic> data, string sheetName) {
XLWorkbook workbook = new XLWorkbook();
var worksheet = workbook.Worksheets.Add(sheetName);
worksheet.Cell(1, 1).InsertTable(data);
}
接下来,您需要将紧密耦合抽象为HttpContext
有一些关于使用HttpContext
Don't mock HttpContext 他不喜欢被嘲笑! :)
你要问的问题是what am I trying to achieve?
。在这种情况下,我们希望将工作簿保存为某些内容。是的,在这种情况下是HttpContext
响应,但它可能是其他的。为此我们需要一个抽象
public interface IWriteWorkbook {
void Write(XLWorkbook workbook, string bookName);
}
您稍后可以在派生类中包含您喜欢使用的HttpContext
。
void Write(XLWorkbook workbook, string bookName) {
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
HttpContext.Current.Response.AddHeader("content-disposition", String.Format(@"attachment;filename={0}.xlsx", bookName.Replace(" ", "_")));
using (MemoryStream memStream = new MemoryStream())
{
workbook.SaveAs(memStream);
memStream.WriteTo(HttpContext.Current.Response.OutputStream);
memStream.Close();
}
HttpContext.Current.Response.End();
}
这也可以改进,但这不在这篇文章的一边。
在所有更改之后,您重构的方法看起来像这样。
public interface IExcelExporter {
void ExportToExcel(IEnumerable<dynamic> data, string bookName, string sheetName);
}
public class ExcelExport : IExcelExporter {
IGetWorkBook workbookgGetter;
IWriteWorkbook workbookWriter;
public ExcelExport (IGetWorkBook workbookgGetter,IWriteWorkbook workbookWriter) {
this.workbookgGetter = workbookgGetter;
this.workbookWriter = workbookWriter;
}
public void ExportToExcel(IEnumerable<dynamic> data, string bookName, string sheetName)
{
XLWorkbook workbook = workbookgGetter.GetWorkBook(data, sheetName);
void workbookWriter.Write(workbook,bookName);
}
}
好的,嗯......这很多。不觉得你会那么多吗?但最终还是值得的。我认为? :)
现在我们需要定位控制器。
public class MyExcelController: Controller {
public MyExcelController(IExcelExporter exporter){
ExcelExport = exporter;
}
IExcelExporter ExcelExport{get; private set;}
[ActionName("ExportData")]
public ActionResult ExportData()
{
ExcelExport.ExportToExcel(_dbaccess.GetAllData(), "Workbook", "Worksheet");
return RedirectToAction("Index");
}
}
请注意,在所有这些之后原始控制器动作没有改变,而周围的一切都有:)甜蜜!!。
现在我们已经准备好嘲笑和测试我们的内心。
您可以测试IGetWorkBook.GetWorkBook
您可以测试IWriteWorkbook.Write
您可以测试ExcelExport.ExportToExcel
确保它们都按预期运行。