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