This chapter describes how to test rules from Rules Designer of Oracle JDeveloper by using the Rules Test Framework provided by Oracle Business Rules. It also discusses how to test rules and Decision Tables by creating an Oracle Business Rules Function. In addition, it covers at runtime, how to test a SOA Application that uses Oracle Business Rules through a decision service by using Oracle Enterprise Manager Fusion Middleware Control Console.
The chapter includes the following sections:
Oracle Business Rules provides a test framework that allows you to test rules with complex input parameters. This framework enables you to test rules at the time of designing so that you can validate or refine the rules as per your requirement.
Another way of testing rules is by defining a test function, where you can construct the input, execute rules, and validate the output. Because inputs are constructed and outputs are validated programmatically, test functions are typically used for simple tests, and the test framework is used for comprehensive tests. In addition, this test function is active only for functions that do not take any parameters and only return boolean values.
Oracle Business Rules provides an 'out-of-the-box' functionality that enables you to test whether the rules you are defining works fine with a given set of inputs at the time of designing. The granularity of testing provided is at the level of decision functions. When you define decision functions in a dictionary, you can define test suites and execute those test suites for each of the decision functions.
Oracle Business Rules supports multiple types of facts, such as Java facts, XML facts, RL facts, and ADFBC facts. The test framework currently only supports XML facts. So, if the decision function, which you have defined, have inputs or outputs referring to non-XML facts, the test framework cannot be used to test the decision function. If you use non-XML facts, a warning or error message is displayed indicating that you cannot use the test feature for that decision function.
To test rules, you need to create a decision function as the prerequisite.
Open Oracle JDeveloper.
From the Application Navigator, open the project file containing the dictionary whose rules you want to test, say BaseDictionary.rules under Business Rules.
In the dictionary section, click Decision Functions to open the list of decision functions.
In the decision functions section, click the Create icon (the plus sign) to display the Edit Decision Function dialog box.
Enter the name of the decision function in the Name field, say
In the Input tab, enter the input name under Name and press Enter. In this example, enter
Select the fact type from the Fact Type list. Ensure that you select XML facts. In this example, select Song as the fact type. Similarly, another input variable with the name as
artists and fact type as Artist has been added.
Select Tree or List as required. See Section 6.2.1, "How to Add or Edit a Decision Function" for more information on tree or list mode rules.
In the Output tab, enter an output name under Name and press Enter. In this example, enter
Select the fact type from the Fact Type list. Ensure that you select XML facts. In this example, select Song.
Under Rulesets & Decision Functions, select the ruleset that you want to invoke from the Available box, and use the shutter (>) icon to move it to the Selected box. In this example, SongArtistRules has been selected.
This example uses sample schema and corresponding facts.
Click OK to create the decision function. Figure 8-1 displays the Edit Decision Function dialog box.
When you create a decision function, two XML schemas (xsd files) get automatically generated to help in testing the decision function. These schemas have suffixes _TestSuite and _Types respectively. Further, these schemas are stored in an xsd folder under the testsuites folder, which can be seen in the Application Navigator as shown in Figure 8-2.
You need to define the test suites, which are created for the decision function, based on the schema with the suffix _TestSuite.
The generated schema files follows the following naming convention:
<DictionaryName>_<DecisionFunctionName>_TestSuite.xsd: This file contains the test suite schema for the decision function. Test Suites created for this decision function should conform to this schema. The following is a sample of the TestSuite.xsd file:
<?xml version = '1.0' encoding = 'UTF-8'?> <schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://xmlns.oracle.com/rules/test" targetNamespace="http://xmlns.oracle.com/rules/test" elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns:df="http://xmlns.oracle.com/rules/BaseDictionary/BaseDF"> <annotation> <documentation> Decision Function Test Suite Schema </documentation> </annotation> <import namespace="http://xmlns.oracle.com/rules/BaseDictionary/BaseDF" schemaLocation="BaseDictionary_BaseDF_Types.xsd"/> <element name="testSuite"> <complexType> <sequence> <element name="decisionFunction" type="string" minOccurs="1" maxOccurs="1"/> <element name="testCase" type="tns:testCaseType" minOccurs="1" maxOccurs="unbounded"/> </sequence> </complexType> </element> <complexType name="testCaseType"> <sequence> <element name="testInput" type="df:parameterList" minOccurs="0" maxOccurs="1"/> <element name="expectedOutput" type="df:resultList" minOccurs="0" maxOccurs="1"/> </sequence> <attribute name="name" type="string" use="required"/> </complexType> </schema>
As you can see in the preceding sample, the schema contains a master
testSuite element, which in turn contains an element called
decisionFunction that defines to which decision function does this test suite corresponds.The
testSuite element also contains one or more
testCase elements. Each
testCase contains a
expectedOutput elements and a name. The
testInput values are the ones that are used as inputs to the test cases and
expectedOutput values are the ones against which the actual outputs are matched. The types of
resultList respectively) have been defined in the subsequent XSD.
<DictionaryName>_<DecisionFunctionName>_Types.xsd: This schema contains two complexTypes elements,
resultList. These two types are used in the TestSuite schema but are defined here. The
parameterList type corresponds to the decision function input and the
resultList type corresponds to the decision function output. This is because a decision function has specific inputs and outputs. When you write a test case for a decision function, then the test case input need to correspond to the inputs accepted by the decision function and the expected output need to correspond to the decision function outputs.
paramaterList and the
resultList are single complexTypes. For example, a decision function requires 10 inputs and 5 outputs, then the
parameterList type will be a single ComplexType that collectively defines 10 different elements that need to be provided as the decision function input.
The following is a sample of the Types.xsd:
<?xml version = '1.0' encoding = 'UTF-8'?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://xmlns.oracle.com/rules/BaseDictionary/BaseDF" attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:tns="http://xmlns.oracle.com/rules/BaseDictionary/BaseDF" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:rules="http://xmlns.oracle.com/bpel/rules" xmlns:ns1="http://xmlns.oracle.com/rulestest/datamodel"> <import namespace="http://xmlns.oracle.com/rulestest/datamodel" schemaLocation="../../xsd/XMLFactTypes2.xsd"/> <import namespace="http://xmlns.oracle.com/bpel/rules" schemaLocation="DecisionFunctionPrimitiveTypes.xsd"/> <complexType name="parameterList"> <sequence> <element name="tSongElement" type="ns1:tSong"/> <element ref="ns1:Artist"/> </sequence> </complexType> <complexType name="resultList"> <sequence> <element name="tSongElement" type="ns1:tSong"/> </sequence> </complexType> </schema>
Every time there is an update to the decision function, the corresponding two schemas get updated. For example, if you change the name of the decision function, then the names of the associated schemas are changed. If you delete the decision functions, the corresponding schemas get deleted.Even changes to the inputs and outputs of the decision function results in the associated schemas getting changed. So a decision function and its corresponding test schemas are always in sync.
In case you make any changes to the decision function, for example delete the decision function, typically the schemas get deleted. When you click the Undo icon on the dictionary toolbar, the decision function is retrieved. However, the corresponding schemas remain deleted. You need to manually regenerate the schemas for the decision function in this case. So the sync between the decision function and its corresponding test schemas is not supported in undo and redo operations.
To manually regenerate the schemas:
Click the Generate test suite schemas for all decision functions icon on the dictionary toolbar as shown in Figure 8-3.
When you click the icon to regenerate the test suite schemas, a bulk regeneration activity takes place, and all the test suite schemas pertaining to all the available decision functions in the dictionary gets regenerated. If the schemas already exist, those are overwritten.
This activity is particularly used in the following cases:
When you have deleted or modified the decision function and have undone the changes: This results in the decision function and the associated schemas getting out of sync. To get them in sync, you use this option so that the schemas are regenerated to correspond to the decision function.
When you migrate old dictionaries: Consider a situation when you already have dictionaries from earlier releases with a number of decision functions defined and you want to use the rules testing feature for defining test suites for those decision functions to test them. In this case, either you have to open each decision function in the editor window after migrating, and then click the OK button. This would generate the corresponding test suite schemas. However, this is time-consuming when you have hundreds of decision functions. In this case, you can use the option of regenerating the schemas at one go.
You need to ensure that the migrated decision functions have XML facts as inputs and outputs, else the inputs and outputs defined in the test suite schema files will be empty.
Once you have created the decision function for testing the rules, you can test rules.
To test rules:
Select the decision function name, say TestDF in this case, in the dictionary page and then click the Test button to display the Decision Function Test dialog box.
Click the Create icon (the plus sign) to display the Create Test Suite dialog box.
Enter the name for the test suite, say
TestDFTestSuite1 and click OK as displayed in Figure 8-4.
Click Close in the Decision Function test dialog box.
When you create a test suite, a <test suite name>.xml file gets automatically generated and gets stored in the <base dictionary name> folder under the rules folder inside the testsuites folder. You can view the file in the Application Navigator window. For every test suite that you create, a corresponding XML file gets generated.
However, the newly created test suite file is empty, which does not contain any test case, input definitions, or output definitions.
Open the <test suite name>.XML and write the required test cases that conform to the test suite XSD file, in this case the TestDF XSDs corresponding to the decision function under test.
The following is a sample test suite file containing test cases:
<?xml version = '1.0' encoding = 'UTF-8'?> <testSuite xmlns="http://xmlns.oracle.com/rules/test" xmlns:ns1="http://xmlns.oracle.com/bpel/rules" xmlns:ns2="http://xmlns.oracle.com/rules/BaseDictionary/BaseDF" xmlns:ns3="http://xmlns.oracle.com/rulestest/datamodel"> <decisionFunction>G}-733d3b8f:12f76ddad3a:-7c02</decisionFunction> <testCase name="TestDFTestSuite1_TestCase1"> <testInput> <ns2:tSongElement> <ns3:Title>Come What May</ns3:Title> <ns3:Composer>Artist</ns3:Composer> <ns3:Length>PT3M2S</ns3:Length> <ns3:Year>2010</ns3:Year> <ns3:Artist> <ns3:name>MJ</ns3:name> <ns3:age>20</ns3:age> <ns3:recordLabel>BMG Music</ns3:recordLabel> </ns3:Artist> </ns2:tSongElement> <ns3:Artist> <ns3:name>MJ</ns3:name> <ns3:age>20</ns3:age> <ns3:recordLabel>BMG Music</ns3:recordLabel> </ns3:Artist> </testInput> <expectedOutput> <ns2:tSongElement> <ns3:Title>Come What May</ns3:Title> <ns3:Composer>MJ</ns3:Composer> <ns3:Publisher>BMG Music</ns3:Publisher> <ns3:Length>PT3M2S</ns3:Length> <ns3:Year>2010</ns3:Year> <ns3:Artist> <ns3:name>MJ</ns3:name> <ns3:age>20</ns3:age> <ns3:recordLabel>BMG Music</ns3:recordLabel> </ns3:Artist> </ns2:tSongElement> </expectedOutput> </testCase> </testSuite>
Save the test suite file.
Open the dictionary page, select the decision function name (say TestDF), and click the Test button to display the Decision Function test dialog box.
Select TestDFTestSuite1 from the Test Suite list and click Run Test as shown in Figure 8-5.
This executes all the test cases in the test suite file.
You can see the test details for the decision function in a tabular form.
The details contain the test suite name, the overall result, and the test case details, such as:
The test case name
The result of the test case
The trace info such as which are the facts that were asserted, which are the rules that were activated, which are the rules that were fired and the resultant change in facts.
Figure 8-6 displays the test results.
The Comments section in the Results page displays any error details in case a test case fails.
You may have a situation where your test suite XML file does not conform to the test suite XSD file. In that case when you open the Decision Function Test window, in the Test Suite list, adjacent to the test suite name, a yellow warning triangle appears as shown in Figure 8-7.
If you try to run an erroneous test suite, you will get the following error message:
If the test suite XML file is malformed, then the test suite name does not appear in the list of test suites in the Decision Function Test window. In addition, for an invalid dictionary , when you test the Decision Function, the following error message is displayed:
Dictionary is invalid, fix validation errors and try again.
Consider a situation, where you have a base dictionary and a custom dictionary. The custom dictionary has a link to the base dictionary.
Now, navigate to the Decision Functions section of the custom dictionary. Note that the list of decision functions in the custom dictionary includes the decision functions from the linked/base dictionary. You can test the decision functions of the base dictionary from the custom dictionary.
In case your test case fails, the Results page displays the probable reasons of failure in the Comments section.
A test case can fail due to the following reasons:
The expected output specified for the test case is different from the actual output as the following:
The Comments section clearly states that there is a mismatch between the expected output and the actual output.
The test case executes, but no output is generated as the following:
You can see that the Comments section displays that the test generated no results and some more details on the probable cause.
The test case executes, but multiple outputs are generated as the following:
The Comments section displays that multiple outputs were generated on test execution along with some details on the probable cause.
The test case does not fire any rule as the following:
This can be because the asserted fact failed to activate any rule resulting in no rules getting fired. So, the Comments section indicates that this may be due to a rule modelling error, because in all probabilities, the provided input failed to match any rule condition.
You can test rulesets by creating a decision function and calling the decision function from Rules Designer with an Oracle Business Rules function. In the body of the Oracle Business Rules function you create input facts, call a decision function, and validate the facts output from the decision function. For more information, see Section 6.1, "Introduction to Decision Functions" and Section 2.5, "Working with Oracle Business Rules Functions".
Confirm that your dictionary is valid.
For more information on dictionary validation, see Section 4.4.4, "How to Validate a Dictionary"
In Rules Designer, select the Functions navigation tab.
In the Functions area click the Create... icon.
Enter the function name in the Name field, or use the default name.
Select the return type from the Return Type list.
For a test function, select
In the Arguments table, confirm that there are no arguments. For a test function, you cannot specify any arguments.
In the Body area, enter the test function body.
In the body of the test function you can call a decision function using
assign new to call and get the return value of the decision function (in the body of the test function you create input facts, call a decision function, and validate the facts output from the decision function).
A decision function call returns a
List. Thus, to test a decision function in a test function you do the following:
You create the input data as required for the decision function input arguments.
You call the decision function with the arguments you create in the test function.
You place results in a
List, for example, in the following:
assign new List resultsList = DecisionFunction_1(testScore)
Figure 8-8 shows a test function that calls a decision function.
Select the function and click the Test Function icon.
The function is executed. The output is shown in a Function Test Result dialog, as Figure 8-9 shows.
Click OK to dismiss the Function Test Result dialog.
You can use Oracle Business Rules Functions to test decision functions from within Rules Designer. Keep the following points in mind when using a test function:
The Test Function icon is gray if the dictionary associated with the test Oracle Business Rules Function contains any validation warnings. The Test Function icon is only shown when the dictionary validates without warnings.
To enable logging you can call
watch.all(). For more information on RL Language functions, see Oracle Fusion Middleware Language Reference Guide for Oracle Business Rules. In this guide,
RL.watch.all() is an alias for the RL Language function
As an alternative to the example shown in Figure 8-8, you can enter the function body that is shown in Example 8-1. This function runs and shows the
RL.watch.all() output. The dialog shows "Test Passed" when the grade is in the B range as shown in Figure 8-10. The dialog shows "Test Failed" when the grade asserted is not in the B range, as shown in Figure 8-11.
call RL.watch.all() assign new TestScore testScore = new TestScore() modify (testScore, name: "Bill Reynolds", testName: "Math Test", testScore: 81) assign new TestGrade testGrade = (TestGrade)DecisionFunction_1(testScore).get(0) return testGrade.grade == Grade.B
In a SOA application that uses Oracle Business Rules with a Decision Service you can test rules at runtime with Oracle Enterprise Manager Fusion Middleware Control Console Test function.
For more information on using the Test function, see Oracle Fusion Middleware Administrator's Guide for Oracle SOA Suite and Oracle Business Process Management Suite.