Modified: 
websites/staging/sling/trunk/content/documentation/tutorials-how-tos/testing-sling-based-applications.html
==============================================================================
--- 
websites/staging/sling/trunk/content/documentation/tutorials-how-tos/testing-sling-based-applications.html
 (original)
+++ 
websites/staging/sling/trunk/content/documentation/tutorials-how-tos/testing-sling-based-applications.html
 Mon Jun  4 07:41:23 2012
@@ -82,12 +82,10 @@
         <a href="/">Home</a>&nbsp;&raquo&nbsp;<a 
href="/documentation.html">Documentation</a>&nbsp;&raquo&nbsp;<a 
href="/documentation/tutorials-how-tos.html">Tutorials & How-Tos</a>
       </div>
       <h1>Testing Sling-based applications</h1>
-      <h1 id="testing-sling-based-applications">Testing Sling-based 
applications</h1>
-<p>Automated testing of OSGi components and services can be challenging, as 
many of them depend on other services that must be present or simulated for 
testing.</p>
+      <p>Automated testing of OSGi components and services can be challenging, 
as many of them depend on other services that must be present or simulated for 
testing.</p>
 <p>This page describes the various approaches that we use to test Sling 
itself, and introduces a number of tools that can help testing OSGi and 
HTTP-based applications.</p>
 <div class="toc">
 <ul>
-<li><a href="#testing-sling-based-applications">Testing Sling-based 
applications</a><ul>
 <li><a href="#unit-tests">Unit tests</a></li>
 <li><a href="#tests-that-use-a-jcr-repository">Tests that use a JCR 
repository</a></li>
 <li><a href="#mock-classes-and-services">Mock classes and services</a><ul>
@@ -99,51 +97,56 @@
 <li><a href="#http-based-integration-tests">HTTP-based integration 
tests</a></li>
 <li><a href="#summary">Summary</a></li>
 </ul>
-</li>
-</ul>
 </div>
 <h2 id="unit-tests">Unit tests</h2>
 <p>When possible, unit tests are obviously the fastest executing ones, and 
it's easy to keep them close to the code that they're testing. </p>
 <p>We have quite a lot of those in Sling, the older use the JUnit3 TestCase 
base class, and later ones use JUnit4 annotations. Mixing both approaches is 
possible, there's no need to rewrite existing tests.</p>
 <h2 id="tests-that-use-a-jcr-repository">Tests that use a JCR repository</h2>
-<p>Utility classes from our <a href="">commons/testing</a> module make it easy 
to get a real JCR repository for testing. That's a bit slower than pure unit 
tests, of course, but this only adds 1-2 seconds to the execution of a test 
suite.</p>
+<p>Utility classes from our <a 
href="https://svn.apache.org/repos/asf/sling/trunk/bundles/commons/testing";>commons/testing</a>
 module make it easy to get a real JCR repository for testing. That's a bit 
slower than pure unit tests, of course, but this only adds 1-2 seconds to the 
execution of a test suite.</p>
 <p>The <code>RepositoryProviderTest</code> in that module uses this technique 
to get a JCR repository.</p>
 <p>Note that our utilities do not cleanup the repository between tests, so you 
must be careful about test isolation, for example by using unique paths for 
each test.</p>
 <h2 id="mock-classes-and-services">Mock classes and services</h2>
 <p>The next step is to use mock classes and services to simulate components 
that are needed for testing. This makes it possible to test OSGi service 
classes without an OSGi framework.</p>
-<p>We have a number of custom-written mock services in Sling, like <a 
href="">MockNodeType</a> for example. These handwritten mocks implement just 
what's needed for their tests, so they might not be reusable as is.</p>
-<p>In other cases we use <a href="">jmock</a> to help create mock objects 
without having to write much code - such mocking libraries take care of the 
plumbing and allow you to write just the bits of code that matter (often with 
funny syntaxes). The tests of the 
[org.apache.sling.event|https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/event/]
 bundle, for example, make extensive use of such mock services.</p>
+<p>We have a number of custom-written mock services in Sling, like <a 
href="https://svn.apache.org/repos/asf/sling/trunk/bundles/commons/testing/src/main/java/org/apache/sling/commons/testing/jcr/MockNodeType.java";>MockNodeType</a>
 for example. These handwritten mocks implement just what's needed for their 
tests, so they might not be reusable as is.</p>
+<p>In other cases we use <a href="http://www.jmock.org/";>jmock</a> to help 
create mock objects without having to write much code - such mocking libraries 
take care of the plumbing and allow you to write just the bits of code that 
matter (often with funny syntaxes). The tests of the <a 
href="https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/event/";>org.apache.sling.event</a>
 bundle, for example, make extensive use of such mock services.</p>
 <p>The problem with mocks is that it can become hard to make sure you're 
actually testing something, and not just "mocking mocks". At a certain level of 
complexity, it becomes quicker and clearer to actually start an OSGi framework 
for automated tests.</p>
 <h3 id="side-note-injecting-services-in-private-fields">Side note: injecting 
services in private fields</h3>
 <p>To inject (real or fake) services in others for testing, without having to 
create getters and setters just for this, we use a reflection-based trick, as 
in this example:</p>
-<p><DIV class="code panel" style="border-style: solid;border-width: 1px;"><DIV 
class="codeHeader panelHeader" style="border-bottom-width: 
1px;border-bottom-style: solid;"><B>setting a private field via 
reflection</B></DIV><DIV class="codeContent panelContent">
-    // set resource resolver factory
-    // in a ServletResolver object which has a private resourceResolverFactory 
field</p>
-<div class="codehilite"><pre><span class="x">ServletResolver servletResolver = 
....</span>
-<span class="x">Class</span><span class="cp">&lt;?</span><span 
class="o">&gt;</span> <span class="nx">resolverClass</span> <span 
class="o">=</span> <span class="nx">servletResolver</span><span 
class="o">.</span><span class="nx">getClass</span><span 
class="p">()</span><span class="o">.</span><span 
class="nx">getSuperclass</span><span class="p">();</span>
-<span class="k">final</span> <span class="nx">java</span><span 
class="o">.</span><span class="nx">lang</span><span class="o">.</span><span 
class="nx">reflect</span><span class="o">.</span><span class="nx">Field</span> 
<span class="nx">resolverField</span> <span class="o">=</span> <span 
class="nx">resolverClass</span><span class="o">.</span><span 
class="nx">getDeclaredField</span><span class="p">(</span><span 
class="s2">&quot;resourceResolverFactory&quot;</span><span class="p">);</span>
-<span class="nx">resolverField</span><span class="o">.</span><span 
class="nx">setAccessible</span><span class="p">(</span><span 
class="k">true</span><span class="p">);</span>
-<span class="nx">resolverField</span><span class="o">.</span><span 
class="nx">set</span><span class="p">(</span><span 
class="nx">servletResolver</span><span class="p">,</span> <span 
class="nx">factory</span><span class="p">);</span>
-</pre></div>
+<table class="codehilitetable"><tr><td class="linenos"><div 
class="linenodiv"><pre>1
+2
+3
+4
+5
+6
+7
+8</pre></div></td><td class="code"><div class="codehilite"><pre><span 
class="c1">// set resource resolver factory</span>
+<span class="c1">// in a ServletResolver object which has a private 
resourceResolverFactory field</span>
 
+<span class="n">ServletResolver</span> <span class="n">servletResolver</span> 
<span class="o">=</span> <span class="o">....</span>
+<span class="n">Class</span><span class="o">&lt;?&gt;</span> <span 
class="n">resolverClass</span> <span class="o">=</span> <span 
class="n">servletResolver</span><span class="o">.</span><span 
class="na">getClass</span><span class="o">().</span><span 
class="na">getSuperclass</span><span class="o">();</span>
+<span class="kd">final</span> <span class="n">java</span><span 
class="o">.</span><span class="na">lang</span><span class="o">.</span><span 
class="na">reflect</span><span class="o">.</span><span class="na">Field</span> 
<span class="n">resolverField</span> <span class="o">=</span> <span 
class="n">resolverClass</span><span class="o">.</span><span 
class="na">getDeclaredField</span><span class="o">(</span><span 
class="s">&quot;resourceResolverFactory&quot;</span><span class="o">);</span>
+<span class="n">resolverField</span><span class="o">.</span><span 
class="na">setAccessible</span><span class="o">(</span><span 
class="kc">true</span><span class="o">);</span>
+<span class="n">resolverField</span><span class="o">.</span><span 
class="na">set</span><span class="o">(</span><span 
class="n">servletResolver</span><span class="o">,</span> <span 
class="n">factory</span><span class="o">);</span>
+</pre></div>
+</td></tr></table>
 
 <h2 id="pax-exam">Pax Exam</h2>
-<p><a href="">Pax Exam</a> allows you to easily start an OSGi framework during 
execution of a JUnit test suite.</p>
-<p>We currently use it for our <a href="">Sling installer integration 
tests</a> for example. As parts of the installer interact directly with the 
OSGi framework, it felt safer to test it in a realistic situation rather than 
mock everything.</p>
+<p><a href="http://team.ops4j.org/wiki/display/paxexam/Pax+Exam";>Pax Exam</a> 
allows you to easily start an OSGi framework during execution of a JUnit test 
suite.</p>
+<p>We currently use it for our <a 
href="https://svn.apache.org/repos/asf/sling/trunk/installer/it";>Sling 
installer integration tests</a> for example. As parts of the installer interact 
directly with the OSGi framework, it felt safer to test it in a realistic 
situation rather than mock everything.</p>
 <p>Such tests are obviously slower than plain unit tests and tests that use 
mocks. Our installer integration tests, using Pax Exam, take about a minute to 
execute on a 2010 macbook pro.</p>
 <h2 id="sling-testing-tools-server-side-junit-tests">Sling testing tools: 
server-side JUnit tests</h2>
-<p>The <a href="">Sling testing tools</a> include a module that executes JUnit 
tests server-side, in a Sling instance. This allows integration tests to run in 
a realistic environment, and could also be used for self-testing production 
systems.</p>
-<p>As I write this, we are not using those tools to test Sling itself, but we 
have a <a href="">complete example</a> of integration tests that use them to 
run server-side JUnit tests, including automatic setup of the test Sling 
instance.</p>
+<p>The <a href="/documentation/development/sling-testing-tools.html">Sling 
testing tools</a> include a module that executes JUnit tests server-side, in a 
Sling instance. This allows integration tests to run in a realistic 
environment, and could also be used for self-testing production systems.</p>
+<p>As I write this, we are not using those tools to test Sling itself, but we 
have a <a 
href="https://svn.apache.org/repos/asf/sling/trunk/testing/samples/integration-tests";>complete
 example</a> of integration tests that use them to run server-side JUnit tests, 
including automatic setup of the test Sling instance.</p>
 <h2 id="http-based-integration-tests">HTTP-based integration tests</h2>
 <p>The highest level of integration is testing a complete Sling instance via 
its HTTP interface.</p>
-<p>We use this technique to test Sling itself: the <a 
href="">launchpad/integration-tests</a> module defines the tests (462 of them 
as I write this), and the 
[launchpad/testing|https://svn.apache.org/repos/asf/sling/trunk/launchpad/testing]
 module executes them, after setting up a Sling instance from scratch (which is 
quite easy as Sling is just a runnable jar). </p>
+<p>We use this technique to test Sling itself: the <a 
href="https://svn.apache.org/repos/asf/sling/trunk/launchpad/integration-tests";>launchpad/integration-tests</a>
 module defines the tests (462 of them as I write this), and the <a 
href="https://svn.apache.org/repos/asf/sling/trunk/launchpad/testing";>launchpad/testing</a>
 module executes them, after setting up a Sling instance from scratch (which is 
quite easy as Sling is just a runnable jar). </p>
 <p>A simple mechanism (described in README files in these modules) allows 
individual tests to be executed quickly against a previously started Sling 
instance, to be able to write and debug tests efficiently.</p>
 <p>The test code could be made simpler using the fluent HTTP interfaces 
defined in the Sling testing tools described above, but the launchpad tests 
were written before that module was created, and as they're stable there's no 
reason to rewrite them. If you're planning on using this technique for your own 
applications, we recommend looking at the Sling testing tools instead of these 
"legacy" tests - but the basic technique is the same.</p>
 <p>One problem with these launchpad tests is that the tests of all Sling 
modules are defined in a single testing module, they are not co-located with 
the code that they test. This could be improved by providing the tests in 
bundles that can be created from the same Maven modules that the code that they 
test.</p>
 <h2 id="summary">Summary</h2>
 <p>Combining the above testing techniques has worked well for us in creating 
and testing Sling. Being able to test things at different levels of integration 
has proved an efficient way to get good test coverage without having to write 
too much boring test code.</p>
       <div class="timestamp" style="margin-top: 30px; font-size: 80%; 
text-align: right;">
-        Rev. 1341347 by fmeschbe on Tue, 22 May 2012 08:25:18 +0000
+        Rev. 1345850 by fmeschbe on Mon, 4 Jun 2012 07:40:42 +0000
       </div>
       <div class="trademarkFooter"> 
         Apache Sling, Sling, Apache, the Apache feather logo, and the Apache 
Sling project


Reply via email to