I am attempting to develop an XML schema (XSD) to represent a set of unit tests for some code. (Specifically, I am testing Oracle PL/SQL stored procedures.)
I would like to have something that represents:
- the procedure itself
- the data used for each test (both arguments to be supplied to the procedure, and data to be loaded into the database before beginning the test(s))
- the expected result of each test
Each procedure can have multiple tests, but I think I would like to only have the tests for one procedure in each XML file.
Below is the schema I have so far: any comments or suggestions would be welcomed!
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://www.example.com/TestData"
elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.example.com/TestData">
<complexType name="ProcedureType">
<complexContent>
<extension base="tns:AbstractProcedureType">
</extension>
</complexContent>
</complexType>
<complexType name="FunctionType">
<complexContent>
<extension base="tns:AbstractProcedureType">
<attribute name="ReturnType" type="tns:DataTypeType"></attribute>
</extension>
</complexContent>
</complexType>
<complexType name="AbstractProcedureType" abstract="true">
<sequence>
<element name="PackageName" type="string" minOccurs="0" maxOccurs="1"></element>
<element name="Name" type="string" minOccurs="1" maxOccurs="1"/>
<element name="Arguments" type="tns:ArgumentsType"
minOccurs="1" maxOccurs="1" />
</sequence>
</complexType>
<complexType name="ArgumentType">
<attribute name="Name" type="string" use="required"/>
<attribute name="DataType" type="tns:DataTypeType"
use="required"/>
</complexType>
<simpleType name="DataTypeType">
<restriction base="string">
<enumeration value="VARCHAR2"/>
<enumeration value="NUMBER"/>
</restriction>
</simpleType>
<complexType name="TestType">
<sequence>
<choice maxOccurs="1" minOccurs="1">
<element name="Procedure" type="tns:ProcedureType"></element>
<element name="Function" type="tns:FunctionType"></element>
</choice>
<element name="Instance" type="tns:TestInstanceType"></element>
</sequence>
</complexType>
<complexType name="TestInstanceType">
<sequence>
<element name="Arguments" type="tns:ArgumentType"
maxOccurs="unbounded" minOccurs="0">
</element>
<element name="ExpectedResult"
type="tns:ExpectedResultType" maxOccurs="1" minOccurs="1">
</element>
</sequence>
</complexType>
<complexType name="ExpectedResultType">
<attribute name="Type" use="required">
<simpleType>
<restriction base="string">
<enumeration value="value"></enumeration>
<enumeration value="exception"></enumeration>
<enumeration value="null"></enumeration>
<enumeration value="nothing"></enumeration>
<enumeration value="query"></enumeration>
</restriction>
</simpleType>
</attribute>
</complexType>
<complexType name="ArgumentsType">
<sequence>
<element name="Argument" type="tns:ArgumentType" maxOccurs="1" minOccurs="0"></element>
</sequence>
</complexType>
<element name="Tests" type="tns:TestsType"></element>
<complexType name="TestsType">
<sequence>
<element name="Test" type="tns:TestType" maxOccurs="unbounded" minOccurs="0"></element>
</sequence>
</complexType>
</schema>
1 Answer 1
- I would move
PackageName
andName
elements of theAbstractProcedureType
to attributes. - I don't think you need an
AbstractProcedureType
, just have aProcedureType
andFunctionType
derived from it. - it's not clear why
ArgumentsType
may have either 0 or 1 argument... I would say that it should havemaxOccurs="unbounded"
- I would make
Arguments
element optional inProcedureType
andFunctionType
(minOccurs="0"
), and require at least one argument if the node is present.
Now let's move to global changes...
- Since you want to have a single procedure/function per XML we can move the declaration of procedure right under the root node.
- I removed some of the named complextypes in favor of in-place type definitions
- You can add some referential constraints to XSD (e.g. argument names in test should match procedure/function declaration).
As a result of these changes I've got the following XSD:
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://www.example.com/TestData"
elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.example.com/TestData">
<element name="Tests" type="tns:TestsType">
<key name="Argument.Name">
<selector xpath="tns:Procedure/tns:Arguments/tns:Argument | tns:Function/tns:Arguments/tns:Argument" />
<field xpath="@Name" />
</key>
</element>
<complexType name="TestsType">
<sequence>
<choice maxOccurs="1" minOccurs="1">
<element name="Procedure" type="tns:ProcedureType" />
<element name="Function" type="tns:FunctionType" />
</choice>
<element name="Test" type="tns:TestInstanceType" minOccurs="0" maxOccurs="unbounded" />
</sequence>
</complexType>
<complexType name="ProcedureType">
<sequence>
<element name="Arguments" minOccurs="0" maxOccurs="1">
<complexType>
<sequence>
<element name="Argument" minOccurs="0" maxOccurs="unbounded">
<complexType>
<attribute name="Name" type="string" use="required" />
<attribute name="DataType" type="tns:DataTypeType" use="required" />
</complexType>
</element>
</sequence>
</complexType>
</element>
</sequence>
<attribute name="PackageName" type="string" use="optional" />
<attribute name="Name" type="string" use="required" />
</complexType>
<complexType name="FunctionType">
<complexContent>
<extension base="tns:ProcedureType">
<attribute name="ReturnType" type="tns:DataTypeType" use="required" />
</extension>
</complexContent>
</complexType>
<simpleType name="DataTypeType">
<restriction base="string">
<enumeration value="VARCHAR2" />
<enumeration value="NUMBER" />
</restriction>
</simpleType>
<complexType name="TestInstanceType">
<sequence>
<element name="Argument" minOccurs="0" maxOccurs="unbounded">
<complexType>
<attribute name="Name" type="string" use="required" />
<attribute name="Value" type="string" use="required" />
</complexType>
<keyref name="Argument.Name.Exists" refer="tns:Argument.Name">
<selector xpath="." />
<field xpath="@Name" />
</keyref>
</element>
<element name="ExpectedResult" type="tns:ExpectedResultType" maxOccurs="1" minOccurs="1" />
</sequence>
</complexType>
<complexType name="ExpectedResultType">
<attribute name="Type" use="required">
<simpleType>
<restriction base="string">
<enumeration value="value" />
<enumeration value="exception" />
<enumeration value="null" />
<enumeration value="nothing" />
<enumeration value="query" />
</restriction>
</simpleType>
</attribute>
</complexType>
</schema>
What I would do next:
- Create several elements for different expected result types (query, exception, etc) and define corresponding attributes and elements on them
- You can also replace generic
Argument
with typed elements, that will allow you to define even more constraints on values of arguments in tests