2016-07-28 28 views
1

Wie soll ich die folgende GetWorksheetPart Methode testen:Mocking OpenXML mit Moq

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); 
    } 
} 

Wo IExcelDocument und SpreadsheetDocumentWrapper der Wrapper-Schnittstellen sind:

public interface IExcelDocument 
{ 
    WorksheetPart GetWorksheetPart(ISpreadsheetDocument excelDoc, string sheetName); 
} 

public interface ISpreadsheetDocument 
{ 
    Sheet GetSheet(string name); 

    WorksheetPart GetPartById(string id); 
} 

Hier ist die Hülle selbst.

public class SpreadsheetDocumentWrapper : ISpreadsheetDocument 
{ 
    private SpreadsheetDocument excelDoc; 

    public SpreadsheetDocumentWrapper(SpreadsheetDocument excelDoc) 
    { 
     this.excelDoc = excelDoc; 
    } 

    public Sheet GetSheet(string sheetName) 
    { 
     return excelDoc.WorkbookPart.Workbook.Descendants<Sheet>() 
        .SingleOrDefault(s => s.Name == sheetName); 
    } 

    public WorksheetPart GetPartById(string id) 
    { 
     return (WorksheetPart)excelDoc.WorkbookPart.GetPartById(id); 
    } 
} 

Schließlich ist der Test, den ich für GetWorksheetPart umzusetzen versucht. Problem mit diesem ist, dass ich nicht sicher bin, wie man diese Funktionalität prüft. Idee ist, einen WorksheetPart den Blattnamen und das Tabellenkalkulationsdokument zu erhalten.

public class Test 
{ 
    [TestClass()] 
    public class ExcelUpdateLogicTests 
    { 
     [TestMethod()] 
     public void Excel_GetWorkseetPartTest() 
     { 
      Mock<ISpreadsheetDocument> mockSpreadhseet = new Mock<ISpreadsheetDocument>(); 
      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<IExcelDocument> mockExcelDocument = new Mock<IExcelDocument>(); 
      WorksheetPart mockWorkseet = mockExcelDocument.Object 
       .GetWorksheetPart(mockSpreadhseet.Object, "sheet"); 

      Assert.IsTrue(mockWorkseet.GetIdOfPart(mockWorkseet) == id); 
     } 
    } 
} 

Hier ist der allgemeine OpenXML Strukturbaum für Tabellen:

   Spreadsheet 
         |   
       WorkbookPart  
     /  |    \ 
    Workbook WorkbookStylesPart WorksheetPart 
     |   |    | 
    Sheets  StyleSheet  Worksheet 
     |      /  \  
    (refers to    SheetData  Columns 
    Worksheetparts)   | 
          Rows 

Antwort

1

Da ExcelDocument ist das System im Test dann gibt es keine Notwendigkeit IExcelDocument zu verspotten ist. Sie sollten Mock/Stub/fälschen die Abhängigkeiten benötigt, um das SUT

Jetzt testen konnte ich Ihren Test bekommen, wie dies zu passieren ...

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>(); 
      worksheetPart.Worksheet = new Worksheet(new SheetData()); 

      // Add a sheets list. 
      Sheets sheets = spreadsheetDocument.WorkbookPart.Workbook.AppendChild<Sheets>(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); 
     } 
    } 
} 

Der Prozess so jedoch tun einige Fragen aufgeworfen, das aktuelle Design.

Wenn der ganze Sinn der Erstellung der Abstraktion war, die Implementierungsdetails zu verbergen und die enge Kopplung auf dem externen Framework zu reduzieren, um die Dinge einfacher zu machen und zu testen dann scheint eine tatsächliche SpreadsheetDocument erstellen und es für den Test umwickeln scheint redundant .

Viele der Teile des Frameworks sind aufgrund ihrer internen Generierung schwer nachzuahmen. Ich würde die hinter anderen Abstraktionen verstecken, aber angesichts dessen, dass ich nicht genug über das Endziel dieses Systems weiß, kann ich nicht sagen, welche Designstruktur Sie verwenden sollten.

+0

Danke für die Antwort. Ich stimme Ihrem Kommentar zur Redundanz zu. Angesichts Ihres Tests sieht es so aus, als wäre der 'SpreadsheetDocumentWrapper' redundant und ich könnte direkt das 'ExcelDocument'-Objekt testen, das im Speicher geladen ist. Ich habe einen Test mit 'Moq' und' Verify' gemacht. Könntest du dir das ansehen und deinen Kommentar abgeben warum man über das andere https://dotnetfiddle.net/hVHvlM? –

+1

Ich habe den Test überprüft und es funktioniert. Aber während der Test besteht und Ihre Verifikationsaufrufe bestehen, ist das 'mockWorksheet'' null'. Mein Rat wäre, zu versuchen, Ihre Interaktion mit OpenXML-Teilen auf einer höheren Ebene zu abstrahieren und zu vermeiden, die Teile bloßzustellen, die Implementierungsdetails zu sein scheinen. – Nkosi

+0

Sie haben Recht, das 'mockWorksheet' ist null. Es überprüft nur Methodenaufrufe. Wenn du höheres Niveau sagst, was genau meinst du? Ist es etwas, was du schon gezeigt hast oder ist das etwas anderes in dir? Wenn dies hilft, ist die Idee für die Anwendung, Zeilen in das ".xlsx" -Dokument einzufügen und es gibt keine Benutzeroberfläche, reines Backend. –