简体   繁体   English

使用Moq模拟自定义收藏

[英]Mock a Custom Collection using Moq

I have the following types in a 3rd party library 我在第3方库中有以下类型

public interface IWorkbook : IPrintable
{
    ...
    IWorksheets Worksheets { get; }
}

The worksheets interface is 工作表界面是

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

I have a method that I want to unit test that takes an IWorkbook and iterates through the contained worksheets. 我有一个要进行单元测试的方法,该方法采用IWorkbook并遍历包含的工作表。 My problem is how I can use Moq to create a mock collection for IWorksheets . 我的问题是如何使用Moq为IWorksheets创建模拟集合。 The IWorksheet interface is IWorksheet界面是

public IWorksheet
{
    ...
    public Name { get; set; } // This is the only property I am interested in.
}

So how can I generate a fake IWorkbook which has a fake collection ( IWorksheets ) of IWorksheet s? 所以,我怎么能生成一个假IWorkbook其中有一个假的集合( IWorksheets的) IWorksheet S'

I have started out with 我已经开始

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

    List<IMock<IWorksheet>> sheetMockList = new List<IMock<IWorksheet>>();
    foreach (string name in fakeSheetNames)
    {
        Mock<IWorksheet> tmpMock = new Mock<IWorksheet>();
        tmpMock.Setup(p => p.Name).Returns(name);
        sheetMockList.Add(tmpMock);
    }

    var mockWorksheets = new Mock<IWorksheets>();
    mockWorksheets.Setup(p => p).Returns(sheetMockList);
    ...
}

But I cannot do this as (obviously) 但是我不能这样做(显然)

cannot convert from 'System.Collections.Generic.List>' to 'SpreadsheetGear.IWorksheets' 无法从“ System.Collections.Generic.List>”转换为“ SpreadsheetGear.IWorksheets”

How can I mock the IWorksheets collection? 如何模拟IWorksheets集合?


So I now have the following code to create my mocks as per the answer below 所以我现在有以下代码按照下面的答案创建我的模拟

    [TestClass]
public class WorkbookStrucutreProviderTests
{
    private Mock<IWorkbookSet> mockWorkbookSet;
    private readonly List<string> parentPrefixes = new List<string>() { "__", "wsg" };

    [TestInitialize]
    public void Initialize()
    {
        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);
        }

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

        mockWorkbookSet = new Mock<IWorkbookSet>();
        mockWorkbookSet
            .Setup(p => p.Workbooks.GetEnumerator())
            .Returns(workbookMockList.GetEnumerator());
    }

    [TestMethod]
    public async Task StrucutreGenerationAsyncTest()
    {
        WorkbookStructureProvider provider = new WorkbookStructureProvider();
        await provider.GenerateWorkbookStructureAsync(mockWorkbookSet.Object);

        foreach (var item in provider.Structure)
        {
            Trace.WriteLine("--" + item.Name);
            if (item.HasChildren)
            {
                foreach (var child in item.Children)
                {
                    Trace.WriteLine("-- --" + child.Name);
                }
            }
        }
    }

But in the GenerateWorkbookStructureAsync() method I have this bit of code 但是在GenerateWorkbookStructureAsync()方法中,我有这段代码

bool IsUserCostWorkbook = false;
if (workbook.Worksheets.Cast<IWorksheet>().Any(
    ws => ws.Name.CompareNoCase(Keywords.Master)))
{
    // TODO Extra check for UserCost template.
    IsUserCostWorkbook = true;          
}

and here the workbook.Worksheets collection is empty. 这里的workbook.Worksheets集合为空。 I thought my mock GetEnumerator would handle this; 我以为我的模拟GetEnumerator可以解决这个问题; it doesn't. 没有。

So how can I mock the IWorksheets so that I can do the following? 那么,如何模拟IWorksheets以便可以执行以下操作?

foreach (var ws in workbook.Worksheets.Cast<IWorksheet>())
{
    ...
}

The following example passes when tested 以下示例在测试时通过

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

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

        worksheetMockList.Add(worksheet);
    }

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

    var workbook = mockWorkbook.Object;

    //Act
    bool IsUserCostWorkbook = false;
    if (workbook.Worksheets.Cast<IWorksheet>()
        .Any(ws => ws.Name.Equals("Master", StringComparison.InvariantCultureIgnoreCase))) {
        IsUserCostWorkbook = true;
    }

    //Assert            
    Assert.IsTrue(IsUserCostWorkbook);
}

Sorry for pseudo code: 对不起,伪代码:

var fakeWorksheet = new Mock<IWorksheet>();
//You can use AutoFixture here to auto-populate properties or you can set only required props
fakeWorksheet.Setup(p => p.Name).Returns("TestName");
var worksheetsMock = new Mock<IWorksheets>()
//here mock some members that you need
worksheetsMock.Setup(w => w.Add()).Returns(fakeWorksheet.Object);
var workbookMock = new Mock<IWorkbook>();
workbookMock.Setup(w => w.Worksheets).Returns(worksheetsMock.Object);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM