如何正确测试此方法?

时间:2016-04-14 13:45:16

标签: c# asp.net-mvc unit-testing memorystream

我有一个方法(下面),它从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");
}

我该如何测试这种方法?

2 个答案:

答案 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

确保它们都按预期运行。