我有一种情况,在MS Dynamics Crm中它使用密封类和只读属性返回一些对象(我只能假设使用内部构造函数或内部属性集)。这些家伙不会从我可以使用的界面继承。显然,如果我控制了这段代码,我会有更多的控制权,但因为它在底层的MS Dynamics框架中,我有点卡住了。
我想要模拟/覆盖的类称为AliasedValue。我想嘲笑它的原因是我试图模拟对动态的调用,并想假装我得到了一些别名值。
所以这就是场景,我想创建一个Dynamics将返回的示例实体......就像这样:
var new_entity = new Entity("new_entity")
{
Attributes = new AttributeCollection
{
{"new_name", "BR"},
{"createdon", DateTime.Now.AddDays(-1).Date},
{"new_field", "My field"},
{"new_contact", new AliasedValue {*****} }
}
};
所以我引用了一个“联系人”实体(实时它以AliasedValue的形式返回)。在测试时,我想确保我的代码处理可能在此字段中返回的某些值(例如,它知道如何处理别名值,如果没有返回链接的联系人,它不会爆炸,等等)。
因此,如果您点击了AliasedValue的链接,您会发现这些属性是只读的...所以我无法设置测试数据......
接下来,我打算创建自己的课程并覆盖整个事情......但它已经密封......
除此之外,正如你可能已经猜到的那样,Moq并不喜欢试图模仿一个密封的班级。
我已经读过我需要购买一些“更好”的模拟框架才能做到这一点,但我真的不想为了解决这个问题而花费一些额外的钱。
任何人都有一个很好的小解决方案让我绕过这个?
澄清更新
返回的方法示例如下。我有一个服务,将被嘲笑返回上述对象。或者实际返回的是包含上述对象的集合。所以就是这样:
var service = new Mock<IOrganizationService>();
service
.Setup(s => s.RetrieveMultiple(null))
.Returns(new EntityCollection (new List<Entity> {new_entity}));
这很好,我可以返回上面的实体并用它做我想做的事。所以,在我创建了上面的实体后,我通过我的模拟服务返回它,我在“EntityCollection”中得到了上述实体。一旦我拥有了我的实体,我就按如下方式访问该属性:
var aliasedContact = (AliasedValue)new_entity.Attributes["new_contact"];
也许我很傻但我无法得到答案(由Lunivore解决)......(添加评论以获得反馈......)
答案 0 :(得分:6)
通过添加一个非常简单的适配器类从第三方库中抽象出来,您可以通过检查来测试它。而不是扩展您的目标类,只需将您的新类组合在其上面。它可以具有相同的方法名称,相同的属性等(虽然它不必) - 它只是委托给密封的类。
如果你有一个类返回你的密封类,请将它们包装起来。所以它可能看起来像这样:
var crmWrapper = new MSDynamicsCrmWrapper(_myMsDynamicsCrm);
var entityWrapper = crmWrapper.AliasedValue(url);
并且crmWrapper将执行:
public EntityWrapper AliasedValue(Url url)
{
var entity = delegateCrm.AliasedValue(url);
return new EntityWrapper(entity);
}
简单。您只需要委派您实际使用的那些方法。
这不仅允许你嘲笑课程,而且如果下一版本的MS Dynamics稍微改变了API,或者结果是奇怪的行为或性能不佳,它可以让你控制。此外,您正在将API缩小到您实际使用的位,因此代码可能更容易维护。
计算中没有任何其他抽象层无法解决......
答案 1 :(得分:0)
为了模拟密封类,非虚拟方法或静态成员通常需要一个基于探查器的模拟框架,以便能够拦截所有调用。我所知道的唯一框架就是Microsoft Moles。
对于Visual Studio 2012,Moles已重命名为Fakes,并将包含在安装中。对于Visual Studio 2010,您需要单独下载它。由于它是基于探查器的框架,因此您需要使用其跑步者moles.runner.exe
运行测试,以便设置探查器。
前段时间我写了一篇博文,描述了在Moles下运行NUnit测试的过程,您可以在以下位置查看:
Unit Testing with NUnit and Moles Redux
另一种选择是遵循Lunivore回答的方向并添加一个抽象层。我自己更喜欢用工具来解决这个问题,但我必须事先建议你,Moles不是那么容易使用的。其他基于探测器的模拟框架(如TypeMock Isolator或JustMock)可能更容易使用,但它们是商业解决方案。