Dan*_*air 7 silverlight wcf proxy asynchronous moq
我有一个典型的Silverlight应用程序与WCF服务,我使用slsvcutil.exe生成标准客户端代理与Web服务进行通信.我正在尝试编写单元测试,我正在尝试使用Silverlight单元测试框架和Moq来模拟代理并删除服务依赖项以进行测试.
我是Moq的新手,在模拟异步调用进行服务调用时,自动在模拟代理上自动引发各种已完成事件有很多麻烦.
为了使代理"可模拟",我为生成的代理调用及其完成的事件创建了自己的简单接口:
public interface IServiceProxy
{
void TestAsync(TestRequest request);
void TestAsync(TestRequest request, object userState);
event EventHandler<TestCompletedEventArgs> TestCompleted;
}
Run Code Online (Sandbox Code Playgroud)
我还将生成的代理对象子类化为实现该接口:
public class MyServiceProxy : GeneratedServiceClient, IServiceProxy, ICommunicationObject
{
// ... overloaded proxy constructors
}
Run Code Online (Sandbox Code Playgroud)
在查看Moq文档之后,我正在尝试设置模拟以期望TestAsync()调用并立即使用EventArgs中的结果引发TestCompleted事件:
[TestMethod]
public void Test_Returns_Expected()
{
var mockProxy = new Mock<IServiceProxy>();
var result = new TestResponse() { Value = true };
this.mockProxy.Setup(
p => p.TestAsync(It.IsAny<TestRequest>()))
.Raises(p => p.TestCompleted += null, new TestCompletedEventArgs(new object[] { result }, null, false, null));
// rest of the test to actually use the mock and assert things
}
Run Code Online (Sandbox Code Playgroud)
一切都很好,但是当我尝试使用模拟运行任何类型的测试并设置断点时,当我调用TestAsync()时,TestCompleted事件永远不会被引发.
是否有任何明显的我遗漏或有关在Silverlight中模拟这些类型的异步服务代理的更好的想法?
谢谢!
编辑:
更清楚我实际上要测试的是一个帮助类,它使用一个实例IServiceProxy
并通过接受Action<TResponse, Exception>
回调参数而不是在我的ViewModel中处理回调事件来为我的ViewModel提供更清晰的服务接口.我理解如何模拟这个以直接测试我的ViewModel但我认为首先测试助手类会很好.
这是我所说的一个例子:
public class HelperClient : IServiceHelper
{
private IServiceProxy proxy;
public HelperClient(IServiceProxy proxy)
{
this.proxy = proxy;
// register to handle all async callback events
this.proxy.TestCompleted += new EventHandler<TestCompletedEventArgs>(TestCompleted);
}
public void Test(TestRequest request, Action<TestResponse, Exception> response)
{
this.proxy.TestAsync(request, response);
}
private void TestCompleted(object sender, TestCompletedEventArgs e)
{
var response = e.UserState as Action<TestResponse, Exception>;
if (response != null)
{
var ex = GetServiceException(e);
if (ex == null)
{
response(e.Result, null);
}
else
{
response(null, ex);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以在我的测试中,我真正在做的是模拟ISerivceProxy并将其传入并尝试测试服务调用以确保它正确调用Action的包装器:
[TestMethod]
[Asynchronous]
public void Test_Returns_Expected()
{
var mockProxy = new Mock<IServiceProxy>();
var helper = new HelperClient(mockProxy.Object);
bool expectedResult = true;
var result = new TestResponse() { Value = expectedResult };
this.mockProxy.Setup(
p => p.TestAsync(It.IsAny<TestRequest>()))
.Raises(p => p.TestCompleted += null, new TestCompletedEventArgs(new object[] { result }, null, false, null));
helper.Test(new TestRequest(), (response, ex) =>
{
Assert.AreEqual(expectedResult, response.Value);
EnqueueTestComplete();
});
}
Run Code Online (Sandbox Code Playgroud)
问题是模拟代理对象永远不会引发TestCompleted事件,因此我的响应操作永远不会被调用来完成测试(即使测试似乎成功完成,Assert也从未实际运行).很抱歉这么长的帖子,只是试图向您展示尽可能多的代码.
编辑2
添加[Asynchronous]
并调用EnqueueTestComplete()
我意识到我可能需要让测试等待事件被提出.这并没有真正的帮助,事件仍然没有提出,所以测试只是挂起,永远不会完成.
编辑3
Aliostad的回答是正确的,我的设置期望的签名与实际的Test()签名不匹配,允许我作为第二个参数传递响应Action.愚蠢的错误,但这是阻止Moq提升Completed事件的原因.我还忘记将Test in作为testCompletedEventArgs中的userState对象传递,以便在引发Completed事件时实际调用它.此外,在这种情况下似乎[Asynchronous]
并EnqueueTestCompleted
没有必要.
以下是感兴趣的人的更新测试代码:
[TestMethod]
public void Test_Returns_Expected()
{
var mockProxy = new Mock<IServiceProxy>();
var helper = new HelperClient(mockProxy.Object);
bool expectedResult = true;
var result = new TestResponse() { Value = expectedResult };
Action<TestResponse, Exception> responseAction = (response, ex) =>
{
Assert.AreEqual(expectedResult, response.Value);
};
this.mockProxy.Setup(
p => p.TestAsync(It.IsAny<TestRequest>(), It.IsAny<Action<TestResponse, Exception>>()))
.Raises(p => p.TestCompleted += null, new TestCompletedEventArgs(new object[] { result }, null, false, responseAction));
helper.Test(new TestRequest(), responseAction);
}
Run Code Online (Sandbox Code Playgroud)
模拟事件非常痛苦,单元测试变得脆弱。但正如你所说,没有办法解决这个问题。但通常您会进行尝试测试的调用并阻止当前线程(使用 Sleep 或其他方法),直到引发事件(或超时)。
实际上并不清楚你在测试什么。我可以看到模拟和响应,实际的真实对象在哪里?
我会相应地更新我的答案。
更新
我在这里看到一个问题:
helper.Test(new TestRequest(), (response, ex) =>
{
Assert.AreEqual(expectedResult, response.Value);
EnqueueTestComplete();
});
Run Code Online (Sandbox Code Playgroud)
在最后一条语句中,您将 EnqueueTestComplete(); 并且您断言但此操作永远不会被使用,因为它被传递到最小起订量对象。
此外,当您在( )TestAsync(It.IsAny<TestRequest>()))
中使用两个参数调用它时,您还设置了对(一个参数)的期望,这就是为什么它永远不会被触发,因为未满足期望。HelperClient
this.proxy.TestAsync(request, response);
归档时间: |
|
查看次数: |
2098 次 |
最近记录: |