Section 3: The Test project
In the previous sections we saw how to create the OTC Script files. In this section, we will see how to use the
downloaded test-project to compile the script files and generate the object-conversion source code and execute
them. The
"Getting Started" section covered details on setting up the
"Test project" available in the
download.
The test classes and sample classes:
Note: There are 2 projects in the downloaded zip file - the otc-test and the otc-test-schema
- The otc-test project:
There are a few test classes in the otc-test project with each of them having a different focus which
are explained below. Below is a screenshot of the folder structure of the "otc-test" project.
- The "unittest.CompilerTest.java" compiles the *.otcs files, generates all required
object-conversion code. Details are given in the below topic "Unit Test classes".
- Before running any test class, update the "./src/test/resources/config/otc.yaml" file
and set the right values for the "compiler.paths.sourceCodeDirectory:",
"compiler.paths.tmdDirectory:" and the "compiler.filterPackages:" properties.
- The "unittest.ExecutorTest.java" executes the object conversion code present in the package name
specified during execution. Please go through the code to grasp what is explained here. Details are
given in the below topic "Unit Test classes".
- The "benchmark.jmh.otc.JmhTest.java" class tests the performance of the OTC framework.
- The "benchmark.jmh.mapstruct.JmhTest.java" tests the performance of the Mapstruct framework.
- The otc-test-schema project:
- There are a few example classes from the "otc-test-schema" project used in the OTCS test-case files.
- One of them is the "testcase.examples.converter.TestConverter.java" used in the OTC Script
"execute" command example.
- The other one is the "testcase.examples.helper.TestFactoryHelper.java" used as an
example while trying out test cases using "overrides:". Details in the "Overrides"
section.
- The "com.kronos.airlines.dto.KronosAirlinePassenger" and the
com.athena.airlines.dto.AthenaAirlinePassenger and their child classes are used as source and
target types in the test cases.
- All these classes are annotated with JAXB annotations only for the purpose of generating XML output for
demonstration purposes and to validate them with the test cases. This has got nothing to do with the OTC
framework but rather any POJO is a suitable candidate for the OTC framework.
Unit Test classes:
- "unittest.CompilerTest" -
- This Junit-test class has a test method which calls the "otcsCompiler.compileOtcsFiles()"
method.
- The "otcsCompiler.compileOtcsFiles()" method call triggers a scan of the
"${OTC_HOME}/otcs-unittest/" folder and sub-folders searching for "*.otcs" files if any,
and compiles them if found and then generates the source-code.
- After this method is executed successfully, you will find the generated source code files in the directory
path that is set for the "compiler.paths.sourceCodeDirectory:" property in the
"./resources/otc.yaml" file.
- If you did not set this "compiler.paths.sourceCodeDirectory:" property, then the files will be
generated in "${OTC_HOME}/src" folder. And in that case, you will have to manually copy the
"*.java" files into your project's "src" folder.
- The same goes with the "compiler.paths.tmdDirectory:" property as well. If this property is not
set, then you will have to manually copy the "${OTC_HOME}/tmd" folder into your project's
"resources" folder.
- The "sourceCodeCompiler.compileSourceCode()" method call compiles the generated source code.
Note: The "Compile" button on the OTC Script editor UI also does exactly what this test class does.
- "unittest.ExecutorTest"
- This Junit-test class first creates an instance of "OtcExecutor" by calling
"OtcExecutorImpl.getInstance()" method.
- When an instance of OtcExecutorImpl is created, it internally calls the "otcRegistry.register()"
method to register some metadata files in the "tmd/" folder generated by the framework for internal
use. These files are created when the "*.otcs" files are compiled.
- There are 2 test methods in this test class viz. "runCopyFromSourceObjectTestCases()" which converts a
source object and literals to a target object, and, the "runCopyFromLiteralsTestCases()" method which
creates the target object using only the literals passed in the .otcs file.
- Each of these methods invokes either the "otcExecutor.copyFromSource(...)" or the
"otcExecutor.copyFromLiterals(...)" methods based on need.
- Finally, after the conversion, the output of the new target object is printed. You may choose between the
XML or JSON formats.
Visibility aspects:
Note: It is very important to understand the visibility aspects of the './otc.yaml'
configuration file and the './tmd' folder in different scenarios as explained below -
- When the OTC Script Editor needs to read the './otc.yaml' file.
The OTC Script editor needs to load this file, and it will always look for
"${OTC_HOME}/config/otc.yaml" file. So make sure you update the parameters in this file so that
the editor can pick up the values.
Secondly, when you click on the "Compile" button on the OTC Script Editor UI
(refer to the section "OTC Script Editor"), or, when you invoke the compilation by the test-class
"CompilerTest" (which is explained below), the "*.tmd" files are created. These
files are meant for internal use by the "unittest.ExecutorTest" class or any other test class
in your project which does the same. Therefore, the 'compiler.paths.tmdDirectory:' folder location
that you should configure in the 'otc.yaml' file should be './src/test/resources'
folder of the "otc-test" project (applicable only for testing code - for production code scenario please refer
to the last point below).
- When the "unittest.CompilerTest" class needs to read the './otc.yaml' file.
This test class (explained under the "Unit Testing" topic below) which compiles the ".otcs" files
and generates the source code, or any other test class in your project which does the same, will look for
the './otc.yaml' file first in the classpath. Since this is a 'test class', this file needs to be in
the classpath of the test classes, which means, this file should be under the 'test' folder hierarchy
- i.e './src/test/resources' folder of the 'otc-test' maven project. And so, you need
to copy this file from "${OTC_HOME}/config/" folder to the './src/test/resources'
folder. Please verify if this behavior is the same in the build tool you are using as well. If the file is
not found in the classpath, then it will look for it in "${OTC_HOME}/config/" folder.
Note: Limit the dependence on "${OTC_HOME}" environment variable by the OTC Script Editor only.
Dependence on it either by the test code or the production code is strongly discouraged. So please make sure
the required file and folder is made available in the classpath as explained here in these points.
- When the "unittest.ExecutorTest" class needs to read both the './tmd' folder and the
'./otc.yaml' file.
Same rule as mentioned in the above point on "unittest.CompilerTest" applies to this test class as
well for both the './tmd' folder and the './otc.yaml' file.
- When the classes in production code of your project needs to read both the './tmd' folder and the
'./otc.yaml' file.
The production code classes looks for this folder and the file in the classpath of the production code.
And so, you should copy this file and the folder from under the 'test' folder hierarchy into the 'main'
folder hierarchy - i.e './src/main/resources' folder of the 'otc-test' maven project.
OTC Script Files:
A few points about the OTCS files used as test cases in the sections.
- There are 58 test-case scenarios in the OTCS files located in the "${OTC_HOME}/otc-pretest" folder.
- The object-path mapping combinations of source and target in the sections were created to cover as many
test scenarios as possible. So, the focus is not on what field mappings makes sense but rather the focus
is on the mapping combinations scenarios only in the example test cases.
- The "${OTC_HOME}/otc-pretest" folder is like only a store for all the untested OTCS files.
- Whenever you want to unit-test a specific OTCS file, copy the file or the folder containing the OTCS file
to "${OTC_HOME}/otc-unittest" folder.
- Once a OTCS file is unit-tested, the recommendation is to move them to the "${OTC_HOME}/otc-tested"
folder. The reason to move them out after testing is to avoid repeated compilation of the already tested
OTCS files on every test iteration.
Package structure:
To have the OTC framework generate the source code files to belong to any package structure, create the folder
structure accordingly to match the package / namespace structure you desire.
The data objects:
JAXB objects created from WSDL/XSD are used as data-objects in the test cases. So some points to be noted on the DTOs
used for testing are -
- The downloaded file contains a Maven project named "otcs-test-schema" which contains the DTOs
referred to in all our examples and test-cases in these tutorials. The test-project has a dependency on this
schema project. Import this project into your IDE and build it. Refer to these DTOs for a better
understanding while doing the exercises.
- To facilitate demo of the OTC Script editor UI the compiled ".jar" file with these DTOs are already placed
in "${OTC_HOME}/lib" folder.
- These are created from a schema related to airline travel domain.
- The schema contains all the required classes representing 2 different mock airlines named Kronos airlines
and Athena airlines.
- These DTOs are annotated with JAXB components only for the purpose of generating the XML output in the examples
to help in demonstration only. But, the OTC Framework does not depend on any such annotations.
- The original DTOs were updated with a few additional fields repeated in a few classes with the objective to
cater to the different test scenarios only. So kindly ignore the sanity of such updates.
- To create .otcs files with the data-objects related to your project using the OTC Script Editor UI, package them
into a ".jar" file and place it in the :"${OTC_HOME}/lib" folder. The OTC Script Editor looks for the
types in this folder location.
Source Object XML:
Here is some information about the source object used in all the examples -
- The "./resources/test-samples/Kronos-passenger-map.xml" has the test-data. This file is picked either from the
class path ("resources" folder) or from "${OTC_HOME}"
- The object KronosAirlinePassenger which is used as the source object in the almost all the test cases is
created from this file.
- Having an understanding of this XML will help you to compare and analyze the output generated by the
test-cases in the sections.
- While executing the examples given in the sections, please refer to this file to compare with the generated
output.
Additional info:
Below are some additional important information.
- The last method parameter. All classes implementing the above interfaces and all OTCS generated classes takes
a java.util.Map as the last method parameter. But when will you need this ?
- When you are integrating OTC in your software project, there may be scenarios wherein you may have some
objects in your application to be made available within the generated code or within your custom helper or
your custom converter (custom helpers and converters are explained in detail in later sections) for some
additional processing logic which you want to add. In which case you may put such data in the map and then
invoke the "otcExecutor.copyFromXXX(...)" method on the Executor passing this map as the last
parameter.
- Note: Never add state (instance level objects) to the generated source code as using them in the code
may cause undesired results. Instead, you can choose this option of passing the values in the map.
- There are 2 interfaces which you should know.
- The OTCS generated entry-class implements the "org.otcframework.common.executor.CodeExecutor"
interface.
- Any custom converter you want to write should implement the
"org.otcframework.common.converter.OtcConverter" interface.
Try it out:
In this exercise we will unit test the OTCS files which are provided in the
"${OTC_HOME}/otc-pretest" folder.
- Start your file-manager and copy the "${OTC_HOME}/otc-pretest/cpyvalues1" folder to
"${OTC_HOME}/otc-unittest" folder.
- This folder has a file named "com.athena.airlines.dto.AthenaAirlinePassenger.otcs".
- Set up the "otc-test" maven project in your favourite IDE.
- In the "otc-test" project, open the "./src/test/resources/otc.yaml" file and set the correct values for
"compiler.paths.sourceCodeDirectory:" and "compiler.paths.tmdDirectory:" parameters pointing to
locations within the test project.
for example -
compiler:
paths:
sourceCodeDirectory: D:/projects/otc-test/src/main/java
tmdDirectory: D:/projects/otc-test/src/main/resources
Note: Please refer to the 'Visibility aspects:' topic above..
- Open the "CompilerTest.java" file.
- Right click anywhere within this test class and select the Run or Debug option. The test method compiles the
"*.otcs" file, generates and compiles the source-code.
- After this test method completes successfully, you may choose to review the generated object conversion
source code. Please refer to the "unittest.CompilerTest" sub-topic above for the location details.
- Run "mvn install" from the terminal. This step will put the "./tmd" folder in the classpath.
- Next open the "ExecutorTest.java" file.
- In the "runCopyFromLiteralsTestCases()" method locate the line "String pkg = "...";".
- Ensure it is initialized to "cpyvalues1" as in "String pkg = "cpyvalues1";". This is the package
name (folder which you just copied).
- If the OTCS file does not belong to any package then set this value to null;
- Run the test method - in your IDE (IntelliJ Idea or Eclipse) right click anywhere within the
"runCopyFromLiteralsTestCases()" method and select the Run or Debug option.
- The test method automatically picks the generated code to be executed, executes it and marshals the created
target object AthenaAirlinePassenger to XML / JSON and prints it on the console.
- Next try out the same steps to test another .otcs file.
- First delete the .otcs file ("/cpyvalues1" folder) under "${OTC_HOME}/otc-unittest" - we do not
want the OTCS compiler to repeatedly spend time compiling the same ".otcs" files that was already compiled
and repeatedly generate the source code.
- This time copy the "${OTC_HOME}/otc-pretest/cpysource_mixedpath" folder.
- Run the "CompilerTest" test class.
- In the other test method in the "ExecutorTest" test class, ie. "runCopyFromSourceObjectTestCases()",
remember to change the value of 'pkg' variable to 'pkg = "cpysource_mixedpath;"'.
- Run the test method