Demos Need Not Be Bad Examples


I got sent a link today of a “Walkthrough on WCF 4.0 Service in Silver Light 4.0”. Ignore the spelling for a second, as this is a foreign post. Understandable. Click. Click. You can download a PDF explaining how to create a WCF service for consumption by Silverlight.

Cutting to the chance, here is my issue:

[ServiceContract]
public interface IService1
{
    [OperationContract]
    string GetMessage(string number1, string number2);
}
public class Service1 : IService1
{
    public string GetMessage(string number1, string number2)
    {
        return (Convert.ToInt32(number1) 
+ Convert.ToInt32(number2)).ToString(); } }

Take a second and look at this. I understand that the point here is to demo a simple service and how it works with Silverlight, but think the example through.

Now, let’s break this down. Suppose I create the following test:

namespace WcfService1.Test
{
    [TestClass()]
    public class Service1Test
    {
        [TestMethod()]
        [HostType("ASP.NET")]
        [AspNetDevelopmentServerHost("c:\projects\test\WcfService1\WcfService1", "/")]
        [UrlToTest("http://localhost:8165/")]
        public void GetMessageTest()
        {
            Service1 target = new Service1(); 
string number1 = "1"; string number2 = "2"; string expected = "3"; string actual= target.GetMessage(number1, number2); Assert.AreEqual(expected, actual); } } }

Assuming we set things up correctly, this works fine. Looks like we have a decent service. But what if we actually run one of the easiest rabbit holes:

[TestClass()]
public class Service1Test
{
    [TestMethod()]
    [HostType("ASP.NET")]
    [AspNetDevelopmentServerHost("c:\projects\test\WcfService1\WcfService1", "/")]
    [UrlToTest("http://localhost:8165/")]
    public void GetMessageTest()
    {
        Service1 target = new Service1(); 
        string number1 = "broken"; 
        string number2 = "code"; 
        string expected = "3"; 
        string actual= target.GetMessage(number1, number2);
        Assert.AreEqual(expected, actual);
    }
}

 

If you have been playing along, your tests are likely failing, as testing WCF services with a unit test framework are notorious buggy. Realistically, you need to treat the service as a UI and then move the code into some type of application library (aka, business tier library – although I disagree that UI is an “application tier” (another time?)).

So let’s focus solely on the algorithm for a second. Service changed to:

namespace WcfService1
{
    public class Service1 : IService1
    {
        public string GetMessage(string number1, string number2)
        {
            return Helper.GetMessage(number1, number2);
        }
    }
}

Implementation moved to class (to mimic a business library):

using System;

namespace WcfService1
{
    public class Helper
    {
        public static string GetMessage(string number1, string number2)
        {
            return (Convert.ToInt32(number1) 
+ Convert.ToInt32(number2)).ToString(); } } }

Now I can easily test this and I end up with:

Test method WcfService1.Test.HelperTest.GetMessageTest threw exception:
System.FormatException: Input string was not in a correct format.

Of course it is incorrect format, it is a “real” string and not a number masquerading as a string. What if we run our good friend Pex and Moles (white box testing):

image

At least Nulls don’t fail. Not good.

What is the problem? At first, you should note that there is no input checking. But even an input check would be useless, in a WCF service, if it does not throw the proper fault. As we are reading this from Silverlight, we probably have the service set up as a SOAP service, which means we should throw a SOAP fault message instead of a FormatException exception object. Ouch!

My point here is not to bash an example, but to once again express the need for disclaimers on examples. I had the same beef with some of the Microsoft ASP.NET guys at the last MVP Summit. On some issues we agreed to disagree, which is fine.

Actually, that is not completely true. The Microsoft code I had issue with would have passed a Pex and Moles test, although the test code would have been running as an integration test rather than a unit test. This one simply fails on all counts except passing in a NULL.

Fixing the code? Options:

Throw a soap exception if the strings are not numbers.

I won’t illustrate this, as it means another 1/2 hour up tonight. Perhaps tomorrow?

Try to parse the input. This means you at least return 0 if the strings “broken” and “code” are entered:

public static string GetMessage(string number1, string number2)
{
    int num1 = 0;
    int num2 = 0;

    int.TryParse(number1, out num1);
    int.TryParse(number2, out num2);

    return (Convert.ToInt32(num1) + Convert.ToInt32(num2)).ToString();
}

This is not a perfect solution, by any means, as I doubt a business wants garbage in to equal zero, but it at least gets us around stupid exception errors passed via a web service.

Peace and Grace,
Greg

Twitter: @gbworld

Advertisements

One Response to Demos Need Not Be Bad Examples

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: