使用Moq模拟第三方库时遇到内部类的问题

时间:2012-09-14 12:51:47

标签: c# mocking moq exchangewebservices

我正在尝试使用moq模拟第三方库的方法。 问题是我正在模拟的方法返回一个在这个框架内部的对象,因此我无法实现这一点。

在下面的示例中,ChangeCollection和ItemChange都是内部的,我得到错误:'无法访问内部构造函数'ChangeCollection'here'

我遇到问题找出一个好的解决方案,有人有任何想法吗?

[TestMethod]
public void GetItemsForExistingEMails_should_call_GetItems_atleast_once()
{
    ewsMock = new Mock<IEwsIntegration>();
    ewsMock.Setup(e => e.GetItems()).Returns(new ChangeCollection<ItemChange>);
    var emailService = new EmailService(ewsMock.Object);

    var items = emailService.GetItemsForExistingEMails();

    ewsMock.Verify(e => e.GetItems(), Times.AtLeast(1));
    Assert.AreEqual(0, items.Count());
}

public interface IEwsIntegration
{
    ChangeCollection<ItemChange> GetItems();
}

2 个答案:

答案 0 :(得分:0)

这里有几种可能的选择。

第一个要求您有权访问第三方来源以设置InternalsVisibleTo

http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx

然后,这允许您访问您引用的dll上的内部成员,并在AssemblyInfo.cs中看起来像这样:

[assembly: InternalsVisibleTo("Mynamespace.MyProject.Tests, PublicKey=00240...")]

其次,因为IEwsIntegration是公开来自第三方应用程序的类型,您可以更改它,以便返回自己的类型。这将为您提供第三方应用程序的更好抽象。

在这里,我使用AutoMapper来管理第三方应用程序的返回类型和我自己的类型之间的映射。然后你可以模拟出这个依赖项(我使用IAutoMapperWrapper)并让它在测试中返回你的返回类型的具体含义。

即使你使用自己的自定义转换器,你也可以模拟它返回的内容,并提供你自己类型的一些对象。

答案 1 :(得分:0)

我认为您可以在界面中返回IEnumerable<ChangeItem>。似乎ChangeCollection只是IEnumerable<T>的实现。

public interface IEwsIntegration
{
    IEnumerable<ItemChange> GetItems();
}

然后您只需在设置中返回一个列表

即可
ewsMock.Setup(e => e.GetItems()).Returns(new List<ItemChange>());

<强>更新

由于必须使用仅在具体类上定义的属性,因此必须创建适配器。

首先使用具体类中的成员创建一个接口。

public interface IChangeCollection<T> : IEnumerable<T>
{
    bool MoreChangesAvailable { get; }
    string SyncState { get; }
}

确保从界面返回此类型:

public interface IEwsIntegration
{
    IChangeCollection<ItemChange> GetItems();
}

然后你必须创建一个IChangeCollection<T>的实现,它只是直接调用ChangeCollection的实例。

public class ChangeCollectionAdapter<T> : IChangeCollection<T>
{
    private readonly ChangeCollection _changeCollection;

    public ChangeCollectionAdapter(ChangeCollection changeCollection)
    {
        _changeCollection = changeCollection;
    }

    public bool MoreChangesAvailable 
    { 
        get { return _changeCollection.MoreChangesAvailable; }
    }

    //other members
}