Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Web services testing tool with hierarchical type parsing

0.00/5 (No votes)
17 Jul 2007 2  
An article on building a tool, helping to test web services with hierarchical input/output types

Screenshot - WebServiceGenericTool.jpg

Introduction

The aim of the tool presented in this article is to increase the productivity of webservices testing. There are plenty of tools available for testing web services, from open source -- like Windows Forms web service clients using ServiceDescriptionImporter -- to such monsters as XMLSpy. Yet searching the web, I couldn't find a tool that would allow for quick testing of a webservice having a complicated XML hierarchy -- i.e. not primitive types -- as input. It would be great if such a tool would allow a tester unfamiliar with the details of XML namespaces and SOAP protocol to simply test the business logic of the web service itself, without thinking about the details of XML serialization.

Using the code

The core of this tool is its use of reflection to iterate through types, generated by ServiceDescriptionImporter after it imports WSDL file. It populates the Windows Forms TreeView with a hierarchy of input from a selected web service operation, i.e. a proxy class method. Although this could seem like an easy task, I've faced a number of challenges when trying to build a working solution:

  • It should be possible to edit "writable" nodes, like text, in the hierarchy. This would actually edit the property of some object, which in turn might be a property of some other parent object
  • Although TreeView would list a full hierarchy of input objects, only some properties and sub-properties need to be "enabled" in different test scenarios, i.e. TreeView with checkboxes
  • Some of the properties in the hierarchy can be arrays of objects, adding complexity to populating these properties with values. There is also a variable number of items that could populate the array

The are 2 main classes that this tool uses to achieve its goals: WebServTreeNode and WSDLImporter. WSDLImporter contains static methods for importing of WSDL and parsing resulting objects. WebServTreeNode is an extension of System.Windows.Forms.TreeNode; it is used to store and populate the objects and their container objects. To make parsing of the object easier, the process was divided between 2 methods. parseWebParamType initially parses the object, which could be an array. parseWebParamProps parses the properties of non-array objects.

private static void parseWebParamType(object pObject, 
    WebServTreeNode pNode, PropertyInfo pPropInfo, Array pParentArray)
{
    Type tObjectType = 
        (pParentArray != null) ? 
        pParentArray.GetType() : tObjectType = pObject.GetType();

    if (tObjectType.IsArray)
    {
        tObjectType = tObjectType.GetElementType();

        if (tObjectType.IsArray)
            throw new NotSupportedException(
            NotSupportedExceptionType.MultiDimArrays);

        object oNewContainerObject = Helper.invokeConstructor(tObjectType);

        if (pParentArray != null)
            pParentArray.SetValue(oNewContainerObject, 0);

        WebServTreeNode nNewNode = 
            new WebServTreeNode(String.Format("{0}[]", 
            tObjectType.Name), WebServTreeNodeType.ArrayElement, null, null);

        nNewNode.ArrayObject = pParentArray;
        nNewNode.ArrayIndex = 0;
        pNode.Nodes.Add(nNewNode);
        nNewNode.ValueType = tObjectType;
        nNewNode.Value = oNewContainerObject;

        parseWebParamProps(oNewContainerObject, nNewNode);

    }
    else
    {
        parseWebParamProps(pObject, pNode);
    }

}

private static void parseWebParamProps(object pObject, WebServTreeNode pNode)
{
    Type tObjectType = pObject.GetType();

    //// looping through props

    foreach (PropertyInfo pi in tObjectType.GetProperties())
    {
        WebServTreeNodeType propNodeType = WebServTreeNodeType.Element;
        if (!Helper.isTypeWritable(pi.PropertyType))
        {
            if (pi.PropertyType.IsArray)
                propNodeType = WebServTreeNodeType.Array;
            else
               propNodeType = WebServTreeNodeType.Container;
        }

        WebServTreeNode nNewNode = 
            new WebServTreeNode(pi.Name, propNodeType, pObject, pi);
        pNode.Nodes.Add(nNewNode);

        if (propNodeType == WebServTreeNodeType.Container || 
            propNodeType == WebServTreeNodeType.Array)
        {
            object oNewPropObject = null;
            Array oNewPropArrayObject = null;

            if (propNodeType == WebServTreeNodeType.Array)
            {
               if (pi.PropertyType.GetElementType().IsArray)
                   throw new NotSupportedException(
                   NotSupportedExceptionType.MultiDimArrays);
               oNewPropArrayObject = 
                   Array.CreateInstance(pi.PropertyType.GetElementType(), 1);
            }
            else
                oNewPropObject = Helper.invokeConstructor(pi.PropertyType);

                nNewNode.Value = 
                    (oNewPropArrayObject != null) ? 
                    oNewPropArrayObject : oNewPropObject;
                parseWebParamType(oNewPropObject, 
                    nNewNode, pi, oNewPropArrayObject);
        }
        else
        {
            nNewNode.ValueType = pi.PropertyType;
            nNewNode.Value = Helper.invokeConstructor(pi.PropertyType);
        }
    }
    //// looping through props

}

As you can see, the main task of these methods is to create instances of WebServTreeNode of appropriate type --i.e. WebServTreeNodeType enumeration -- and populate it with references to the object it should populate. The logic of editing properties of the objects as well as "cloning" array element nodes is placed within methods and properties of WebServTreeNode, which proved to be quite a reasonable design decision.

Points of interest

Although the functionality of the tool is all about web services, the "core" of its source code is all about reflection. Object parsing code is not the most effective. It still has some bugs and "scenarios" it does not support, but it was a great exercise in object-orientation, allowing a beginner to learn the intricacies of .NET object structure. Plus, it already proved to be a great helper in testing my current project's webservices. On the other hand, I hope that this tool will prove to be interesting -- at least as idea, if not its source code -- for webservices developers who are interested in .NET and are searching for a way to unit-test webservices. I think that the main part of the source code is clean enough to be easily extendable for new webservice testing scenarios.

History

  • 17 June, 2007 -- Original version posted

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here