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。。这正是我试图调试问题的地方。

Moq multi interfaces

正如我从您的代码中看到的,您正在测试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。