Moq multi interfaces
本文关键字:interfaces multi Moq | 更新日期: 2023-09-27 18:29:39
背景:
我为我的Wcf客户制作了一个简单的代理程序,部分基于网上的例子,部分基于我的需求。
创建客户端代理的用法是:
WcfClientProxy<IServicecontract> clientProxy =
new WcfClientProxy<IServiceContract>();
WcfClientProxy有一个名为Execute的方法,它采用:Expression<Func<TChannel, TResult>>
或Expression<Action<TChannel>>
。
我正在努力实现的目标:
我试图使用Moq来模拟这一点,这样我就可以通过客户端测试对服务合同的调用。
所以嘲笑这样的电话。。
clientProxy.Execute(m=>m.DoSomeAction(5));
问题:
问题是模拟不起作用。我得到这个错误:
"引发异常:System.NullReferenceException:对象引用未设置为对象的实例。"
我的测试服务合同是:
public interface ITestingServiceInterface : System.ServiceModel.IClientChannel
{
string Version();
VersionDetail VersionDetail();
IList<VersionDetail> VersionDetails();
void DoSomeDelete(int itemId);
}
wcf客户端代理接口:
public interface IWcfClientProxy<TChannel> where TChannel : ICommunicationObject
{
bool ThrowOnException { get; set; }
TResult Execute<TResult>(Expression<Func<TChannel, TResult>> operation);
void Execute(Expression<Action<TChannel>> expression);
}
我尝试了设置的测试和模拟。。
private List<ProdItem> items;
private Mock<IWcfClientProxy<ITestingServiceInterface>> mockClientProxy;
[TestInitialize]
public void SettingUp()
{
mockClientProxy = new Mock<IWcfClientProxy<ITestingServiceInterface>>();
items = new List<ProdItem>();
for( int i =0; i<10; i++){
items.Add(new ProdItem { ProdItemId = i, LocalStock = i });
}
}
[TestMethod]
public void SimpleTest()
{
mockClientProxy.Setup(m => m.Execute(x => x.DoSomeDelete(It.IsAny<int>()))).Callback(RemoveItem);
var client = mockClientProxy.Object;
client.Execute(x => x.DoSomeDelete(4));
Assert.AreEqual(9, items.Count);
}
public void RemoveItem()
{
items.RemoveAt(items.Count - 1);
}
这个测试的错误实际上是断言错误,似乎回调从未被命中。
我确信我只是做了一些愚蠢的事。
更新:展示了一个我希望能够测试的例子,如果以上方法有效的话。。
[TestMethod]
public void SimpleTest()
{
mockClientProxy.Setup(m => m.Execute(x => x.DoSomeDelete(It.IsAny<int>()))).Callback(RemoveItem);
var client = mockClientProxy.Object;
var stockHelper = new StockHelper(client);
stockHelper.DeleteItem(5);
Assert.AreEqual(9, items.Count);
}
在上面的文章中,我测试了StockHelper类,该类在其构造函数中使用客户端代理,通过该代理对WCF进行调用。
为了测试StockHelper(或者其他什么),我需要能够模拟客户端及其服务调用。上面的(第一个)恶魔的例子让我在尝试这样做时遇到了问题。
我希望这是有道理的,请注意,我的最终目标不是测试一个mock。。这正是我试图调试问题的地方。
正如我从您的代码中看到的,您正在测试mock。我没有看到你正在测试的任何实物。Mock用于截断正在测试的对象的依赖关系。因此,如果某个类Foo
使用IWcfClientProxy
,则向类Foo
提供该代理的mock。并验证在Foo.Bar()
执行过程中调用了依赖关系的DoSomeDelete
方法。这就是嘲讽的目的。
[TestClass]
public class FooTests
{
private Foo _foo;
private Mock<IWcfClientProxy<ITestingServiceInterface>> _clientProxy;
[TestInitialize]
public void SettingUp()
{
_clientProxy = new Mock<IWcfClientProxy<ITestingServiceInterface>>();
_foo = new Foo(_clientProxy.Object);
}
[TestMethod]
public void SimpleTest()
{
// Act on object being tested
_foo.Bar(5);
// verify it executed correct method on dependency
_clientProxy.Verify(cp => cp.Execute(x => x.DoSomeDelete(5)));
}
}
请记住,在测试Foo
时,您不应该关心_clientProxy
是如何实现的。
在模拟设置中发生了一些奇怪的事情。我认为您设置的匹配参数仅限于函数调用的第一层。你可能需要做一些类似的事情:
mockClientProxy.Setup(m => m.Execute(It.IsAny<Expression<Action<TChannel>>>())).Callback(RemoveItem);
Moq通过在其参数的接口上实现方法来工作,在这种情况下,它是IWcfClientProxy<ITestingServiceInterface>
的接口方法。因此,当您将方法调用设置为Execute时,需要为要执行的参数设置匹配的参数。您在代码中所做的是为特定的委托函数设置一个匹配项,这将永远不会真正匹配任何内容,因为您不会存储它并在以后使用它调用Execute。