Moq多接口

时间:2012-04-02 09:41:42

标签: c# asp.net mocking moq

背景

我已经为我的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);
}

此测试的错误实际上是断言错误,似乎Callback永远不会被命中。

我确信我刚刚做了些蠢事。

更新 显示我希望能够测试上述工作的示例..

[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(或者什么),我需要能够模拟客户端及其服务调用。以上(第1个)示例恶魔 - 直截了当地试图解决这个问题。

我希望这是有道理的,请看我的最终目标不是测试模拟..这就是我必须尝试调试我的问题的地方。

2 个答案:

答案 0 :(得分:2)

正如我从您的代码中看到的那样,您正在测试模拟。我没有看到你正在测试的任何真实物体。模拟用于存储被测对象的依赖关系。因此,如果某个类Foo使用IWcfClientProxy,那么您可以将此代理的模拟提供给类Foo。并验证在调用依赖项的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的实施方式。

答案 1 :(得分:0)

你的模拟设置中有一些奇怪的东西。我认为您设置的匹配参数仅限于第一层函数调用。您可能需要执行以下操作:

mockClientProxy.Setup(m => m.Execute(It.IsAny<Expression<Action<TChannel>>>())).Callback(RemoveItem);

Moq通过在其参数的接口上实现方法来工作,在这种情况下它是IWcfClientProxy<ITestingServiceInterface>的接口方法。因此,当您将方法调用设置为Execute时,您需要为Execute参数设置匹配参数。您在代码中所做的是为特定的委托功能设置一个匹配项,该功能实际上永远不会匹配任何内容,因为您不会将其存储并稍后调用Execute。