Unit Testing
Contents
How to Write Unit Tests
opentaps 1.0
For opentaps 1.0, you would write a set of Junit tests in a class, then define it in an XML testdef file like this:
<test-suite suite-name="entitytests" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.ofbiz.org/dtds/test-suite.xsd"> <test-case case-name="security-tests"><junit-test-suite class-name="com.opensourcestrategies.crmsfa.test.SecurityTests"/></test-case> </test-suite>
You can define multiple tests per testdef xml file. Then, add the testdef file to your ofbiz-component.xml, like this:
<test-suite loader="main" location="testdef/crmsfa_tests.xml"/>
Then, when you do
$ ant run-tests
your tests will be run.
opentaps 0.9
In opentaps 0.9, you would write your Junit tests class and add your it to the base/config/test-containers.xml file, in the "junit-container" at the bottom, like this:
<container name="junit-container" class="org.ofbiz.base.container.JunitContainer"> <property name="base-test" value="org.ofbiz.base.test.BaseUnitTests"/> <property name="entity-test" value="org.ofbiz.entity.test.EntityTestSuite"/> <property name="service-test" value="org.ofbiz.service.test.ServiceEngineTests"/> <property name="crm-security" value="com.opensourcestrategies.crmsfa.test.SecurityTests"/> <!-- your unit tests --> <!-- <property name="usps-test" value="org.ofbiz.shipment.thirdparty.usps.UspsServicesTests"/> <property name="jxunit-test" value="net.sourceforge.jxunit.JXTestCase"/> --> </container>
Then you would do
$ ant run-tests
Your tests will run alongside the existing OFBIZ test suites.
IMPORTANT: Use a "test" delegator to point your tests to a separate database, and make sure it is defined in framework/entity/config/entityengine.xml is set to the right database.
Setting Up For Unit Testing
We recommend that you create a separate database on the same database server for testing purposes and install all demo data into the testing database. Let's say that this database is called "opentaps_testing". Then, edit the file framework/entity/config/entityengine.xml and define opentaps_testing as a new datasource, called "localmysltesting" or "localpostgrestesting". Next, initiate the demo data into the testing database by editing the default delegator:
<delegator name="default" entity-model-reader="main" entity-group-reader="main" entity-eca-reader="main" distributed-cache-clear-enabled="false"> <group-map group-name="org.ofbiz" datasource-name="localXXXtesting"/> </delegator>
Then do an
$ ant run-install
to install all the seed and demo data into the testing database. Then you can edit the default delegator back to your original delegator, and set the test delegator to the testing database:
<delegator name="test" entity-model-reader="main" entity-group-reader="main" entity-eca-reader="main"> <group-map group-name="org.ofbiz" datasource-name="localXXXtesting"/> </delegator>
All unit tests should be run to use the test delegator. This can be done by instantiating the the "test" delegator by name and using that delegator to instantiate a dispatcher. Or you can just write a test suite which extends the OpentapsTests base class, which does it for you.
If you need to modify port settings for the testing instance, you should edit the file framework/base/config/test-containers.xml.
Unit Testing Strategies
These are some strategies for unit testing:
- Transaction comparison - Compare the transaction produced with a sample transaction, possibly pre-loaded into the system. For example, posting a paycheck to the ledger and then comparing with test data of a correct ledger transaction to make sure that they are equivalent.
- State change - Compare the state of the system before and after a transaction has occurred. For example, check the inventry of an item, then ship an order, and check the resulting inventory to make sure that it is correctly decremented. This could get very complex: Shipping an order could cause customer balances, invoices, ledger postings, and inventory changes. Multiple tests could be run off the same transaction event.
- Absolute state check - At all times, certain relationships must hold. For example, the sum of all debits must equal sum of all credits.
Tests should be written against the services that create the original data. For example, if you are writing tests against CRMSFA activity, you can use users from the demo data set, but you should use the CRMSFA activity services to create or update your activities. Otherwise, if you create those activities with some other method, future changes to the services to create activities will not be covered by your unit tests.
Debugging Unit Tests with IntelliJ
The default task for tests will do a global compile. To skip this, you can redefine the run-tests target in build.xml as follows,
<target name="run-tests"> <java jar="ofbiz.jar" fork="true"> <arg value="test"/> </java> </target>
Using a debugger can help speed up development of the unit tests. You can enable debugging by specifying the JVM arguments for your debugging system. For instance, if you have the IntelliJ IDE, the run-tests target becomes,
<target name="run-tests"> <java jar="ofbiz.jar" fork="true"> <jvmarg value="${memory.max.param}"/> <jvmarg value="-Xdebug"/> <jvmarg value="-Xnoagent"/> <jvmarg value="-Djava.compiler=NONE "/> <jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"/> <arg value="test"/> </java> </target>
You should be able to attach the debugger immediately after running ant run-tests. Don't forget to recompile the component where your tests live.
Another tip is to comment out all unnecessary test suites. Unfortunately, this involves searching every ofbiz-component.xml. One way to find them, if you're on a POSIX OS, is to use find,
$ find . -name ofbiz-component.xml -exec grep test-suite {} \; -print