Mocking Asynchronous Calls in Silverlight WCF Proxy using Moq

I have a typical Silverlight application with a WCF service, and I use slsvcutil.exe to create a standard client proxy to communicate with the web service. I am trying to write unit tests and I am trying to use the Silverlight Unit and Moq testing framework to ridicule the proxies and remove the service dependency for testing.

I am very new to Moq, and I have a lot of problems automatically raising various events Completed on the mooed proxy automatically when they make phone calls to simulate asynchronous calls.

To make the proxy server "mockable", I created my own simple interface for the generated proxy calls and their completed events:

public interface IServiceProxy { void TestAsync(TestRequest request); void TestAsync(TestRequest request, object userState); event EventHandler<TestCompletedEventArgs> TestCompleted; } 

I also subclassed the generated proxy object to implement this interface:

 public class MyServiceProxy : GeneratedServiceClient, IServiceProxy, ICommunicationObject { // ... overloaded proxy constructors } 

After looking at the Moq documentation, I am trying to customize the layout to wait for TestAsync () to be called, and immediately raise the TestCompleted event with the result of EventArgs:

 [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 } 

Everything builds fine, but when I try to run some test using the layout and the given breakpoints, the TestCompleted event never fires when I call TestAsync ().

Is there something obvious that I'm missing or any better ideas regarding the ridicule of these types of async proxies in Silverlight?

Thanks!

EDIT:

To be more clear what I'm trying to test, this is a helper class that I made that accepts an IServiceProxy instance and provides a cleaner service interface for my ViewModel to use, taking Action <TResponse, Exception> parameters, rather than dealing with callback events in my ViewModel model. I understand how I could mock this to directly test my ViewModel, but I decided that it would be nice to check the helper class first.

Here is an example of what I'm talking about:

 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); } } } } 

So, in my test, what I'm really doing is mocking ISerivceProxy and passing it on and just trying to test the service call to make sure that the wrapper causing the action is correct:

 [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(); }); } 

The problem is that the mocked proxy object never raises the TestCompleted event, so my response action will never be called to complete the test (although the test seems to complete successfully, Assert never fires). Sorry for such a long post, just trying to show you as much code as possible.

EDIT 2

Added [Asynchronous] and call EnqueueTestComplete() , which, as I understand it, may require the test to wait until the event is raised. It didn’t help, the event never rose anyway, so the test just hangs and never ends.

EDIT 3

Aliostad's answer was correct that my wait wait signature for the installation did not match the actual Test () signature, allowing me to pass the action as a second parameter in response. Stupid mistake, but this is what prevented Mok from raising the Completed event. I also forgot to pass the Action as a userState to TestCompletedEventArgs so that it actually gets called when the Completed event is raised. In addition, [Asynchronous] and EnqueueTestCompleted did not seem necessary in this case.

Here is updated test code for anyone interested:

 [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); } 
+7
asynchronous proxy moq silverlight wcf
source share
2 answers

Mocking events is quite a pain, and unit tests become fragile. But, as you said, there is no way around this. But usually you make a call that you are trying to test and block the current thread (using "Sleep" or other methods) until the event is raised (or time out).

In fact, it is not clear what you are testing. I can see the layout and the answer, where is the actual real object?

I will update the answer accordingly.

UPDATE

I see a problem here:

 helper.Test(new TestRequest(), (response, ex) => { Assert.AreEqual(expectedResult, response.Value); EnqueueTestComplete(); }); 

in the last statement, you add EnqueueTestComplete (); and you affirm, but this action will never be used because it is passed to the moq object.

You also set the wait for TestAsync(It.IsAny<TestRequest>())) (one argument) when you call it with two arguments in HelperClient ( this.proxy.TestAsync(request, response); ), and therefore it never starts because expectations are not fulfilled.

+4
source share

just searched for the asynchronous WCF client and found this question.

To prevent this situation, Moq can .Verify() call p.TestAsync ().

 //will throw MockException if p.TestAsync() has never been called. this.mockProxy.Verify(p => p.TestAsync(It.IsAny<TestRequest>()), Times.Once()); 
0
source share

All Articles