背景
我已经为我的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个)示例恶魔 - 直截了当地试图解决这个问题。
我希望这是有道理的,请看我的最终目标不是测试模拟..这就是我必须尝试调试我的问题的地方。
答案 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。