使用Moq模拟OpenXML
我应该如何测试以下GetWorksheetPart
方法:
public class ExcelDocument : IExcelDocument { private readonly string _filePath; public ExcelDocument(string filePath) { _filePath = filePath; } public WorksheetPart GetWorksheetPart(ISpreadsheetDocument excelDoc, string sheetName) { Sheet sheet = excelDoc.GetSheet(sheetName); if (sheet == null) { throw new ArgumentException( String.Format("No sheet named {0} found in spreadsheet {1}", sheetName, _filePath), "sheetName"); } return excelDoc.GetPartById(sheet.Id); } }
IExcelDocument
和包装器的SpreadsheetDocumentWrapper
接口是:
public interface IExcelDocument { WorksheetPart GetWorksheetPart(ISpreadsheetDocument excelDoc, string sheetName); } public interface ISpreadsheetDocument { Sheet GetSheet(string name); WorksheetPart GetPartById(string id); }
这是包装器本身。
public class SpreadsheetDocumentWrapper : ISpreadsheetDocument { private SpreadsheetDocument excelDoc; public SpreadsheetDocumentWrapper(SpreadsheetDocument excelDoc) { this.excelDoc = excelDoc; } public Sheet GetSheet(string sheetName) { return excelDoc.WorkbookPart.Workbook.Descendants() .SingleOrDefault(s => s.Name == sheetName); } public WorksheetPart GetPartById(string id) { return (WorksheetPart)excelDoc.WorkbookPart.GetPartById(id); } }
最后,我尝试为GetWorksheetPart
实现的GetWorksheetPart
。 这个问题是我不确定如何测试这个function。 想法是根据WorksheetPart
表名称和电子表格文档获取WorksheetPart
。
public class Test { [TestClass()] public class ExcelUpdateLogicTests { [TestMethod()] public void Excel_GetWorkseetPartTest() { Mock mockSpreadhseet = new Mock(); Sheet sheet = new Sheet(); string id = "1"; sheet.Name = "sheet"; sheet.Id = id; mockSpreadhseet.Setup(doc => doc.GetSheet("sheet")).Returns(sheet); mockSpreadhseet.Setup(doc => doc.GetPartById(id)).Returns(????); Mock mockExcelDocument = new Mock(); WorksheetPart mockWorkseet = mockExcelDocument.Object .GetWorksheetPart(mockSpreadhseet.Object, "sheet"); Assert.IsTrue(mockWorkseet.GetIdOfPart(mockWorkseet) == id); } } }
以下是Spreadsheets的一般OpenXML结构树:
Spreadsheet | WorkbookPart / | \ Workbook WorkbookStylesPart WorksheetPart | | | Sheets StyleSheet Worksheet | / \ (refers to SheetData Columns Worksheetparts) | Rows
由于ExcelDocument
是被测系统,因此无需模拟IExcelDocument
。 您应该模拟/存根/伪造测试SUT所需的依赖项
现在我能够让你的测试通过这样的…
public class Test { [TestClass()] public class ExcelUpdateLogicTests { [TestMethod()] public void Given_SheetName_ExcelDocument_Should_GetWorkseetPart() { //Arrange var stream = new MemoryStream();//Avoid having to use actual file on disk var spreadsheetDocument = SpreadsheetDocument.Create(stream, SpreadsheetDocumentType.Workbook); // Add a WorkbookPart. WorkbookPart workbookpart = spreadsheetDocument.AddWorkbookPart(); workbookpart.Workbook = new Workbook(); // Add a WorksheetPart. WorksheetPart worksheetPart = workbookpart.AddNewPart(); worksheetPart.Worksheet = new Worksheet(new SheetData()); // Add a sheets list. Sheets sheets = spreadsheetDocument.WorkbookPart.Workbook.AppendChild(new Sheets()); // Append the new worksheet and associate it with the workbook. string expectedId = workbookpart.GetIdOfPart(worksheetPart); string sheetName = "mySheet"; Sheet sheet = new Sheet() { Id = expectedId, SheetId = 1, Name = sheetName }; sheets.Append(sheet); var wrapper = new SpreadsheetDocumentWrapper(spreadsheetDocument); string fakeFilePath = "path"; var sut = new ExcelDocument(fakeFilePath); //Act WorksheetPart result = sut.GetWorksheetPart(wrapper, sheetName); //Assert Assert.IsNotNull(result); var actualId = workbookpart.GetIdOfPart(result); Assert.AreEqual(expectedId, actualId); } } }
然而,这样做的过程提出了一些关于当前设计的问题。
如果创建抽象的全部目的是隐藏实现细节并减少外部框架上的紧密耦合以使事情更容易模拟和测试,那么必须创建一个实际的SpreadsheetDocument
并将其包装用于测试似乎是多余的。
鉴于内部生成,框架的许多部分很难被模拟。 我会隐藏其他抽象背后的东西,但鉴于我对这个系统的最终目标不够了解,我无法建议你应该采用什么样的设计结构。