Normally unit testing is used to verify that state is being altered as expected and interactions are occurring as expected (state based testing or interaction based testing). We also write integration/functional tests to ensure that layers and components are working together correctly in the overall picture.
While in the field I’ve noticed that most tests neglect the attributes of the WCF ServiceContract. Shouldnt these be tested as well? Yes, they definitely should!
You may say …. "OperationContractAttribute is just an attribute that indicates that this method is part of a service contract in a WCF application, so why do I need to test the attribute?"
Good question… consider this scenario:
You’re the developer on a large enterprise system and you’ve created a WCF Service that handles processing sets of data. Depending on the parameters, this data can take hours process. Therefore you’ve decided to implement the "IsOneWay" attribute value on the OperationContractAttribute.
Is One Way explanation:
Use the IsOneWay property to indicate that an operation does not return a reply message.
…
If the IsOneWay property is set to false (the default), even methods that return void result in a reply message. In this case, the infrastructure creates and sends an empty message to indicate to the caller that the method has returned. (Using this approach enables the infrastructure to send SOAP faults back to the client.) Setting IsOneWay to true is the only way to cancel the creation and dispatch of a response message.
Why Testing IsOneWay Matters
Now that you’ve set the IsOneWay value to true in your service, the calling applications can fire off a request and let the service crunch away on the request (remember, in this scenario, it may take hours to complete). This is an expected behavior of your service – having the method return as soon as its sent without waiting for a response message from the service.
Fast forward 4 weeks …. Joe Developer decides to remove the "IsOneWay" value (which in turn changes it to false, which is its default) because its not working for his new application as he expects. Everything works for him now, and he checks in the code to source control. Everything builds on your continuous integration environment. All tests pass, everything looks golden.
The new service updates and application updates get applied to production and almost immediately users start complaining about another line of business application "freezing up" when they click a certain button.
"All of a sudden, when I clicked the <Load Data> button, the application just froze. I just left for lunch and when I came back everything was normal. Now, its doing it again. I’m not sure what’s going on. This application sucks."
You check the app logs, event viewers, traces, etc and then realize that the application IS WORKING but it stops for quite awhile at the service call. The weird thing is that the code does not throw any errors, it just takes forever to return from that call. This problem seems to be a performance problem. If you’re not careful this problem could masquerade itself as another probelm in your mind:
"Is the network slow?"
"Is the service down?"
"Is it doing a retry?"
"Are all the packets getting transmitted?"
The list could go on and on.
The Reason For the Slow Down in the App
Why is the app performing so poorly at this service call? Because IsOneWay was set to false (default when not preset in the attribute values). The app that was written 4 weeks ago expects IsOneWay set to true so it does not block the current thread waiting for a response from the service call.
Since the call is set the value of IsOneWay is set to false, the application is now hanging.
How To Prevent This
The continuous integration environment should have had a test for this. Either unit test or integration test. Unfortunately it did not, and in most companies I don’t see a test for this kind of thing, ever.
To fix this we need to implement a unit test for this attribute. We need to make sure that it is set to TRUE so that we dont break anything.
Code
Below is the code to implement the test for the IsOneWay attribute value.
FooTheory.WcfServiceExample.cs – The service we need to test.
1 using System.ServiceModel; 2 3 namespace FooTheory.WcfServiceExample 4 { 5 [ServiceContract] 6 public interface IFooTheoryWcf 7 { 8 [OperationContract(IsOneWay = true)] 9 void Execute(); 10 11 } 12 }
The Unit Test
FooTheoryWcfContractTests.cs
1 using System; 2 using System.ServiceModel; 3 using FooTheory.WcfServiceExample; 4 using NUnit.Framework; 5 using NUnit.Framework.SyntaxHelpers; 6 7 namespace FooTheory.WcfExampleTests 8 { 9 [TestFixture] 10 public class FooTheoryWcfContractTests 11 { 12 private readonly string ONE_WAY_METHOD_NAME = "Execute"; 13 14 [Test] 15 public void Execute_Should_Be_OneWay() 16 { 17 object[] atts = typeof (IFooTheoryWcf) 18 .GetMethod(ONE_WAY_METHOD_NAME) 19 .GetCustomAttributes(false); 20 21 OperationContractAttribute opAttribute = 22 (OperationContractAttribute) Array.Find(atts, 23 delegate(object obj) 24 { 25 if (obj is OperationContractAttribute) 26 return true; 27 return false; 28 }); 29 30 Assert.That(opAttribute, Is.Not.Null, 31 "Could not find the attribute connected to the method that is needed."); 32 Assert.That(opAttribute.IsOneWay, Is.True, 33 "Method should be marked as IsOneWay for Application X"); 34 } 35 } 36 }
Code Explanation
The unit test uses reflection to get the attribute of OperationContract and then it checks to see if its not null and also checks to see value of the IsOneWay property.
Conclusion
If either one of these asserts fail, the build will break in the continuous integration environment. This will let the dev’s know that something they did broke an expectation on the service contract. Catching this type of problem early in the cycle can help immensely. Not only does it save time, but it saves money in both dev time as well as end user time.
If you don’t catch this early on, you could be calculating the costs of lost time of a couple of devs as well as numerous end users who are using the dependent application(s). If you’re using this Service in a SaaS approach, you could really been in some hot water with those clients that utilizing your service. No one wants to use a service that is unreliable.
So, remember, test early and test often! Get those WCF Attributes under test!
Leave a Reply
You must be logged in to post a comment.