| | 1050 | <title>Integration tests for Nuxeo Runtime applications</title> |
|---|
| | 1051 | <para> |
|---|
| | 1052 | While it's obviously a good thing to unit-test one's code, it's usually not enough for a |
|---|
| | 1053 | module designed to be ran as part of a Nuxeo Runtime application. It's indeed likely in this situation that |
|---|
| | 1054 | the module will depend on services provided by other modules, and even maybe on their default configuration. It's |
|---|
| | 1055 | even not uncommon that a project specific modules consists almost exclusively of calls to generic services provided |
|---|
| | 1056 | by the base software platform. |
|---|
| | 1057 | </para> |
|---|
| | 1058 | |
|---|
| | 1059 | <section xml:id="nuxeo-runtime-test-NXRuntimeTestCase"> |
|---|
| | 1060 | <title>The NXRuntimeTestCase base class</title> |
|---|
| | 1061 | <para><code>org.nuxeo.runtime.test.NXRuntimeTestCase</code> is a base class to write JUnit tests |
|---|
| | 1062 | for Nuxeo Runtime applications. It sets up the Nuxeo Runtime environment (in the <code>setUp</code> method |
|---|
| | 1063 | and provides methods to control bundle and resources loading. It's designed to behave in the same manner in Maven |
|---|
| | 1064 | and Eclipse situations. Therefore resources must be accessed in a way that does not depend on the actual ordering |
|---|
| | 1065 | of classpath.</para> |
|---|
| | 1066 | <section><title>Loading a bundle</title> |
|---|
| | 1067 | <para>To load a whole OSGI bundle, use the <code>deployBundle</code> method, whose parameter is the bundle symbolic |
|---|
| | 1068 | name, as specified in the manifest</para> |
|---|
| | 1069 | </section> |
|---|
| | 1070 | <section><title>Loading one contribution from a bundle</title> |
|---|
| | 1071 | <para>Loading a whole bundle can be too heavy, or bring unwanted default configurations. Therefore, the |
|---|
| | 1072 | <code>deployContrib</code> method is |
|---|
| | 1073 | provided to load just a resource (service definition, extension point contribution, etc.) from a given bundle. |
|---|
| | 1074 | It takes two arguments: the bundle symbolic name, and the path to the contrib from the top of bundle. |
|---|
| | 1075 | </para> |
|---|
| | 1076 | </section> |
|---|
| | 1077 | <section><title>Loading a test resouce</title> |
|---|
| | 1078 | <para>For resources from the test packages, just make an OSGI bundle of the test package, which can be done |
|---|
| | 1079 | by creating the META-INF/MANIFEST.MF at the top of the target jar, and use deployContrib as above. |
|---|
| | 1080 | </para> |
|---|
| | 1081 | </section> |
|---|
| | 1082 | <section><title>Sample usage</title> |
|---|
| | 1083 | <para>The following is an excerpt from <code>org.nuxeo.project.sample</code>: |
|---|
| | 1084 | <programlisting><![CDATA[ |
|---|
| | 1085 | public class TestBookTitleService extends NXRuntimeTestCase { |
|---|
| | 1086 | |
|---|
| | 1087 | private BookTitleService service; |
|---|
| | 1088 | |
|---|
| | 1089 | private static final String OSGI_BUNDLE_NAME = "org.nuxeo.project.sample"; |
|---|
| | 1090 | |
|---|
| | 1091 | private static final String OSGI_TEST_BUNDLE = "org.nuxeo.project.sample.tests"; |
|---|
| | 1092 | |
|---|
| | 1093 | public void setUp() throws Exception { |
|---|
| | 1094 | super.setUp(); |
|---|
| | 1095 | // deployment of the whole nuxeo-project sample bundle |
|---|
| | 1096 | deployBundle(OSGI_BUNDLE_NAME); |
|---|
| | 1097 | |
|---|
| | 1098 | service = Framework.getService(BookTitleService.class); |
|---|
| | 1099 | } |
|---|
| | 1100 | |
|---|
| | 1101 | public void testServiceContribution() throws Exception { |
|---|
| | 1102 | // Lookup is ensured simply by making the 'test' sub-hierarchy a |
|---|
| | 1103 | // bundle of its own, with a MANIFEST file |
|---|
| | 1104 | deployContrib(OSGI_TEST_BUNDLE, "sample-booktitle-test.xml"); |
|---|
| | 1105 | assertEquals("FOOBAR Test", service.correctTitle("foobar")); |
|---|
| | 1106 | } |
|---|
| | 1107 | ]]> |
|---|
| | 1108 | </programlisting> |
|---|
| | 1109 | </para> |
|---|
| | 1110 | </section> |
|---|
| | 1111 | </section> |
|---|
| | 1112 | |
|---|
| | 1113 | <section><title>Frequent patterns</title> |
|---|
| | 1114 | <para>While working on an integration test, it's always worthwile to prescribe clearly what is |
|---|
| | 1115 | to be tested: either API calls to services provided by other modules, consistency with configuration provided |
|---|
| | 1116 | by other modules, default configuration for the module being tested. This is especially important for the |
|---|
| | 1117 | non-regression aspect of the testing and the cost of maintaining the tests.</para> |
|---|
| | 1118 | |
|---|
| | 1119 | <para>The use-cases discussed below require basic knowledge of the Nuxeo ECM framework. Implicitely, it is somehow |
|---|
| | 1120 | assumed that the tested code has to interact with one service. In case of multiple target services, one'd have to |
|---|
| | 1121 | choose a pattern for each of them.</para> |
|---|
| | 1122 | |
|---|
| | 1123 | <section><title>Integration test against base services with testing configuration</title> |
|---|
| | 1124 | <para> We want to check that the API calls from the tested component to other components have the desired effect, but we don't want to rewrite the tests each time the default configuration of the other components change. Typically, this means that we need to deploy the xml contributions that define the services we need, together with the minimal configuration to tie it up together.</para> |
|---|
| | 1125 | |
|---|
| | 1126 | <para>Example: The search service is able to configure its indexes automatically from the schemas and core types declaration. We don't want to have to update tests if someone changes the default config that ships with nuxeo-core. Ideally, this test should use <code>deployBundle</code> to set up core services, test repository, etc. and then work on dedicated schemas and core types that are loaded by <code>deployContrib</code>. |
|---|
| | 1127 | </para> |
|---|
| | 1128 | </section> |
|---|
| | 1129 | |
|---|
| | 1130 | <section><title>Integration test against base services and their default configuration</title> |
|---|
| | 1131 | <para> |
|---|
| | 1132 | One can imagine here a core event listener that uses a given schema, a component that needs access |
|---|
| | 1133 | to the search service to manipulate some specific documents... |
|---|
| | 1134 | </para> |
|---|
| | 1135 | <para>In this case, we need to load the base service and its configuration exactly as they are in the real application and we do want the test to catch errors that are due to a change in said configuration. In this pattern, we'd use <code>deployBundle</code> all over the place. |
|---|
| | 1136 | </para> |
|---|
| | 1137 | <para> |
|---|
| | 1138 | It's likely however that one does not want the test to rely on the default (if any) configuration of the module being tested. If the tested component doesn't carry its configuration but still needs to be deployed within Nuxeo Runtime, <code>deployBundle</code> can be used on itself, and then <code>deployContrib</code> for the test configuration, after the test package has been upgraded to an OSGI bundle. |
|---|
| | 1139 | </para> |
|---|
| | 1140 | <para>Variant: testing of a component and the configuration that comes along. |
|---|
| | 1141 | Just think of your tested module as a "base service."</para> |
|---|
| | 1142 | </section> |
|---|
| | 1143 | <section><title>Reusing test resources from another component</title> |
|---|
| | 1144 | <para> |
|---|
| | 1145 | This is usually neither possible nor recommended. Such situations do appear in the Nuxeo code base, and the proper |
|---|
| | 1146 | solution is to provide the wished resources or classes from a <code>package</code>, precisely like |
|---|
| | 1147 | <code>org.nuxeo.ecm.runtime.test</code> does. |
|---|
| | 1148 | </para> |
|---|
| | 1149 | </section> |
|---|
| | 1150 | </section> |
|---|
| | 1151 | </section> |
|---|
| | 1152 | |
|---|
| | 1153 | <section> |
|---|