2016-08-24 47 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]);