2016-08-24 46 views
3

我想知道我怎麼能嘲笑的索引屬性的選擇,且有這麼多的問題:模擬只讀索引器屬性

  1. Moq an indexed property and use the index value in the return/callback
  2. How to MOQ an Indexed property
  3. How to Moq Setting an Indexed property

等。但在我的情況下,增加了複雜性。索引屬性是隻讀的。所以,我需要能夠測試一段代碼,做以下

if (workbook.Worksheets.Cast<IWorksheet>().Any(
     ws => ws.Name.CompareNoCase(Keywords.Master))) 
{ 
    ... 
} 

,我們有下面的類結構

public interface IWorkbook 
{ 
    IWorksheets Worksheets { get; } 
} 

public interface IWorksheets : IEnumerable 
{ 
    IWorksheet this[int index] { get; } 
    IWorksheet this[string name] { get; } 
    int Count { get; } 
    IWorksheet Add(); 
    IWorksheet AddAfter(IWorksheet sheet); 
    IWorksheet AddBefore(IWorksheet sheet); 
    bool Contains(IWorksheet worksheet); 
} 

public interface IWorksheet 
{ 
    string Name { get; set; } 
} 

所以在我的測試方法,我試圖(和失敗)通過覆蓋GetEnumerator()方法來做到這一點,因爲這正是Cast()所調用的;我這樣做如下:

List<string> fakeSheetNames = new List<string>() 
{ 
    "Master", "A", "B", "C", "__ParentA", "D", "wsgParentB", "E", "F","__ParentC", "__ParentD", "G" 
}; 

List<IWorksheet> worksheetMockList = new List<IWorksheet>(); 
foreach (string name in fakeSheetNames) 
{ 
    Mock<IWorksheet> tmpMock = new Mock<IWorksheet>(); 
    tmpMock.Setup(p => p.Name).Returns(name); 
    tmpMock.Setup(p => p.Visible) 
     .Returns(parentPrefixes.Any(p => name.StartsWith(p)) ? 
      SheetVisibility.Hidden : 
      SheetVisibility.Visible); 

    worksheetMockList.Add(tmpMock.Object); 
} 

Mock<IWorkbook> mockWorkbook = new Mock<IWorkbook>(); 
mockWorkbook 
    .Setup(p => p.Worksheets.GetEnumerator()) 
    .Returns(worksheetMockList.GetEnumerator()); 

// I can't do this as per the threads referenced above, as the property is read only. 
//for (int i = 0; i < worksheetMockList.Count; ++i) 
    //mockWorkbook.SetupGet(p => p.Worksheets[i] = worksheetMockList[i])... 

我怎麼能嘲笑我workbook.Worksheets只讀iterator屬性?


我還有一個抽象層次。我需要將IWorkbook添加到IWorkbooks集合(就像我們爲IWorksheets所做的那樣)。我沒有把這個問題放在原來的問題中,因爲它只是做和IWorksheets一樣的事情,但它怎麼都行不通。這些接口

public interface IWorkbookSet 
{ 
    ... 
    IWorkbooks Workbooks { get; } 
} 

public interface IWorkbooks : IEnumerable 
{ 
    IWorkbook this[int index] { get; } 
    IWorkbook this[string name] { get; } 
    int Count { get; } 
    ... 
} 

所以試圖解決這個我按照下面的巨大嘲諷答案在下面的流行時尚。但是,下面的循環不能按預期工作。

List<string> fakeSheetNames = new List<string>() 
{ 
    "Master", 
    "A", 
    "B", 
    "C", 
    "__ParentA", 
    "D", 
    "wsgParentB", 
    "E", 
    "F", 
    "__ParentC", 
    "__ParentD", 
    "G" 
}; 


Mock<IWorkbook> mockWorkbook = new Mock<IWorkbook>(); 
List<IWorksheet> worksheetMockList = new List<IWorksheet>(); 
foreach (string name in fakeSheetNames) 
{ 
    Mock<IWorksheet> tmpWorksheetMock = new Mock<IWorksheet>(); 
    tmpWorksheetMock.Setup(p => p.Name).Returns(name); 
    tmpWorksheetMock.Setup(p => p.Visible) 
     .Returns(parentPrefixes.Any(p => name.StartsWith(p)) ? 
      SheetVisibility.Hidden : 
      SheetVisibility.Visible); 

    worksheetMockList.Add(tmpWorksheetMock.Object); 
} 
var mockWorksheets = new Mock<IWorksheets>(); 
mockWorksheets.Setup(m => m[It.IsAny<int>()]).Returns<int>(index => worksheetMockList[index]); 
mockWorksheets.Setup(m => m.GetEnumerator()).Returns(worksheetMockList.GetEnumerator()); 

mockWorkbook 
    .Setup(p => p.Worksheets) 
    .Returns(mockWorksheets.Object); 
mockWorkbook.Setup(p => p.Name).Returns("Name"); 
mockWorkbook.Setup(p => p.FullName).Returns("FullName"); 

// This works. 
foreach (IWorksheet ws in mockWorkbook.Object.Worksheets) 
    Trace.WriteLine(ws.Name); 

mockWorkbookSet = new Mock<IWorkbookSet>(); 
var mockWorkbooks = new Mock<IWorkbooks>(); 
List<IWorkbook> workbookMockList = new List<IWorkbook>() { mockWorkbook.Object }; 

mockWorkbooks.Setup(m => m[It.IsAny<int>()]).Returns<int>(index => workbookMockList[index]); 
mockWorkbooks.Setup(m => m.GetEnumerator()).Returns(workbookMockList.GetEnumerator()); 
mockWorkbookSet 
    .Setup(p => p.Workbooks) 
    .Returns(mockWorkbooks.Object); 

// Count is zero here?? 
foreach (IWorkbook wb in mockWorkbookSet.Object.Workbooks) 
    Trace.WriteLine(wb.Worksheets.Count); 

非常感謝。


編輯#2:使用你的代碼,我有一些有趣的現象...

// Setup test. 
var workbookSet = mockWorkbookSet.Object; 
var actual = workbookSet 
    .Workbooks[expectedWorkBooksIndex] 
    .Worksheets[expectedWorkSheetIndex]; 

// This prints "A" - GOOD! 
Trace.WriteLine("Actual " + actual.Name); 

// This passes. 
Assert.AreEqual(expected, actual); 

// This works. 
foreach (IWorksheet ws in mockWorkbook.Object.Worksheets) 
    Trace.WriteLine(ws.Name); 

// This works. 
Trace.WriteLine(mockWorkbookSet.Object.Workbooks[0].Name); 

// This does not write anything - WHY? 
foreach (IWorksheet ws in mockWorkbookSet.Object.Workbooks[0].Worksheets.Cast<IWorksheet>()) 
    Trace.WriteLine(ws.Name); 

// This fails. 
foreach (IWorkbook workbook in workbookSet.Workbooks.Cast<IWorkbook>()) 
    Assert.IsTrue(workbook.Worksheets.Count > 0); 

回答

2

使用

mockWorkSheets 
    .Setup(m => m[It.IsAny<int>()]) 
    .Returns<int>(index => worksheetMockList[index]); 

其中It.IsAny<int>().Returns<int>(index => ...)可以訪問傳遞到模擬 您可以在.Returns方法訪問索引值。

下面的例子顯示設置如何在嘲笑

[TestMethod] 
public void Mock_Readonly_Indexer_Property() { 
    //Arrange 
    var parentPrefixes = new List<string>() { "__", "wsg" }; 
    var fakeSheetNames = new List<string>(){ 
     "Master", 
     "A", 
     "B", 
     "C", 
     "__ParentA", 
     "D", 
     "wsgParentB", 
     "E", 
     "F", 
     "__ParentC", 
     "__ParentD", 
     "G" 
    }; 

    //Worksheets 
    var fakeWorkSheetsList = new List<IWorksheet>(); 
    foreach (string name in fakeSheetNames) { 
     var tmpMock = Mock.Of<IWorksheet>(); 
     tmpMock.Name = name; 
     tmpMock.Visible = parentPrefixes.Any(p => name.StartsWith(p)) ? 
       SheetVisibility.Hidden : 
       SheetVisibility.Visible; 

     fakeWorkSheetsList.Add(tmpMock); 
    } 

    var mockWorkSheets = new Mock<IWorksheets>(); 
    mockWorkSheets.Setup(m => m[It.IsAny<int>()]) 
     .Returns<int>(index => fakeWorkSheetsList[index]); 
    mockWorkSheets.Setup(m => m.GetEnumerator()) 
     .Returns(() => fakeWorkSheetsList.GetEnumerator()); 
    //Assuming a Count property exists 
    mockWorkSheets.Setup(m => m.Count).Returns(fakeWorkSheetsList.Count); 

    //Workbook 
    var mockWorkbook = new Mock<IWorkbook>(); 
    mockWorkbook.Setup(p => p.Name).Returns("Name"); 
    mockWorkbook.Setup(p => p.FullName).Returns("FullName"); 
    mockWorkbook.Setup(p => p.Worksheets).Returns(mockWorkSheets.Object); 

    //Workbooks 
    var fakeWorkbooksList = new List<IWorkbook>() { mockWorkbook.Object }; 

    var mockWorkbooks = new Mock<IWorkbooks>(); 
    mockWorkbooks.Setup(m => m[It.IsAny<int>()]) 
     .Returns<int>(index => fakeWorkbooksList[index]); 
    mockWorkbooks.Setup(m => m.GetEnumerator()) 
     .Returns(() => fakeWorkbooksList.GetEnumerator()); 
    mockWorkbooks.Setup(m => m.Count).Returns(fakeWorkbooksList.Count); 

    //WorkbookSet 
    var mockWorkbookSet = new Mock<IWorkbookSet>(); 
    mockWorkbookSet.Setup(m => m.Workbooks).Returns(mockWorkbooks.Object); 

    var workbookSet = mockWorkbookSet.Object; 

    var expectedWorkBooksIndex = 0; 
    var expectedWorkSheetIndex = 1; 
    var expected = fakeWorkSheetsList[expectedWorkSheetIndex]; 

    //Act 
    var actual = workbookSet 
     .Workbooks[expectedWorkBooksIndex] 
     .Worksheets[expectedWorkSheetIndex]; 

    //Assert 
    Assert.AreEqual(expected, actual); 

    foreach (IWorkbook workbook in workbookSet.Workbooks) { 
     Assert.IsTrue(workbook.Worksheets.Count > 0); 
    } 

} 
+0

非常感謝您的幫助在這裏,但我仍然有這個問題。你可以檢查編輯?我會在適當的時候獎勵你的幫助...... – MoonKnight

+0

@Killercam,你在不同的問題中傳播了同樣的問題。我詢問了其他問題的一些信息,以幫助澄清問題,以便我可以重現您的問題並提供完整的解決方案,但是除非我剛剛展示瞭如何解決您詢問的具體問題的示例。然後你可以將這些反應拼湊起來解決你的整體問題 – Nkosi

+0

對不起。我以一種不夠簡潔的方式,通過另一個線索來了解我所問的問題。我沒有真正掌握(只讀索引器屬性)的問題。我沒有這樣做,因爲其他任何明顯的原因。無論如何,我領先於我自己;編輯不可用。再次感謝您的所有時間,這是非常感謝。 – MoonKnight

2

也許你正在尋找呢?

mockWorkbook.SetupGet(wb => wb.Worksheets[i]).Returns(() => worksheetMockList[i]);