On Mon, December 02, 2013, Paul Bors wrote:

> Have you considered Mockito to mock your POJOs for the test data and
> methods?
> I use that in conjunction with TestNG and then start the wicket app
> providing it mocked DAOs and POJOs.

I've got pretty strong feelings about such frameworks, bluntly
speaking, I consider them harmful. They look like a cool thing
on first glance, but if you've got complex test cases in your
business logic you end up recording complex sequences of mocked
service responses and end up with write-only test code. People
who use them for their code may have different experience, but
since I usually work on large projects in teams of 2-5 people
I've far too often had to understand and repair broken tests 
that were made unnecessarily complex due to the use of Eazymock
or Mockito.

Just for completeness I'm repeating once again what I already
wrote about it a little before in this thread:

> I really don't like mocking services and DAOs at all, because in
> complex application this sooner or later leads you to testing
> against your particular implementation rather than your code's
> contract. In particular when mocking frameworks are used, this
> very easily leads to write-only test code. I've seen this on too
> many occasions and no longer believe that this is a wise
> approach.

> Also one needs to consider that many applications are pretty
> much data-driven (e.g. my system uses a document-based data
> model with nearly 100 different object variants), and loading
> and
> interpreting both schema and data is a crucial piece of the
> application and needs thorough testing, and you really want to
> do this on the real thing rather than on mocked services.

But actually I wanted to report my progress on this issue here,
since this might be of interest for others, too. I succeded with
my approach and implemented my first tests yesterday. My setup
is like this:

1. For testing, I deploy my test librariees into WEB-INF/lib,
so that they can be used within the running webapp. Also I create
a JAR file from all my integration tests and deploy it into the
same location. 

2. I create a wicket page and mount it somewhere (e.g. /test), 
make sure that it cannot be accessed in production environments :)

3. In that page, I locate the JAR with my tests:

| @Nonnull
| public static File getJarForClassName( String packageAndClassName ) {
|     URL url = ReflectionUtil.class.getClassLoader().getResource( 
packageAndClassName );
|     if ( url == null ) {
|         throw new IllegalStateException( "Unable to resolve resource " + 
packageAndClassName );
|     }
|     if ( !"jar".equals( url.getProtocol() ) ) {
|         throw new IllegalStateException( "Wrong protocol for " + 
packageAndClassName + ": " + url.getProtocol() );
|     }
|     String path = url.getPath();
|     if ( path == null ) {
|         throw new IllegalStateException( "No path for " + packageAndClassName 
);
|     }
|     int delimPos = path.indexOf( '!' );
|     if ( delimPos <= 0 ) {
|         throw new IllegalStateException( "Cannot extract JAR path for " + 
packageAndClassName + ": " + path );
|     }
|     String jarPath = path.substring( "file:".length(), delimPos );
|     File result = new File( jarPath );
|     if ( !result.isFile() ) {
|         throw new IllegalStateException( "Something's wrong, no valid file 
for " + packageAndClassName + ": " + jarPath );
|     }
|     return result;
| }

4. Then I set up TestNG in onConfigure():

| TestNG testNG = new TestNG();
| testNG.setTestJar( jarFile.getAbsolutePath() );
| testNG.setExcludedGroups( EXCLUDED_TEST_GROUPS );
| testNG.setGroups( INCLUDED_TEST_GROUPS );
| testNG.setOutputDirectory( outputDir.getAbsolutePath() );
| @SuppressWarnings( "rawtypes" )
| List<Class> reporterList = Collections.<Class> singletonList( 
HTMLReporter.class );
| testNG.setListenerClasses( reporterList );
| int result = 0;
| try {
|     testNG.run();
|     result = testNG.getStatus();
| } catch ( TestNGException ex ) {
|     LOG.error( "Exception caught", ex );
|     error( ex.getMessage() );
|     result = 1;
| }

5. If the result is not 0, I throw an IllegalStateException,
so that my ANT build fails:

| if ( result != 0 ) {
|     throw new IllegalStateException( "tests failed" );
| }

6. Since my tests may run for a while i increase the 
timeout before wicket throws a pagemap-locked exception
in the constructor:

|  if ( !TIMEOUT_FOR_TEST_PAGE.equals( 
VrmsApplication.get().getRequestCycleSettings().getTimeout() ) ) {
|      VrmsApplication.get().getRequestCycleSettings().setTimeout( 
TIMEOUT_FOR_TEST_PAGE );
|  }

7. In ANT I create a test target like this:

| <target name="test-integration" 
depends="check-wget,compile-tests,glassfish-start-if-necessary,glassfish-test-deploy">
|     <antcall target="run-test-integration"></antcall>
| </target>
| 
| <target name="run-test-integration">
|     <exec executable="wget" failonerror="true">
|         <arg line="-O /dev/null --quiet http://localhost:8080/test"; />
|     </exec>
| </target>

Now testing the business logic has become very simple.
I work on real (anonymized production) data, and while I
may not be able to rely on the presence of some particular
objects I have the most realistic distribution of data
that I can dream of. Only thing one needs to make sure is
rolling back changes ones has made during test execution,
thus tests manipulating data usually have a try-finally
block where in the end my changes are undone (I prefer
this to @AfterClass as I rather specifically undo changes
and like to do that as close as possible to the location
where I did change things). This may not be elegant, but
it is by far outweighed by the gains I get from my approach.

Getting this working took me a little more than a working 
day. Setting up an in-memory test data base, test search
index, jmx infrastructure (which in my case are provided
by the glassfish) plus writing all the missing test data
generators for a project of that scale would have taken
me several weeks while hardly giving me any advantage.

Thus for pre-Spring/Guice legacy code this approach may
be worthwhile.

Cheers,

M'bert

-- 
----------- / http://herbert.the-little-red-haired-girl.org / -------------
=+= 
Attachment? See: http://piology.org/ILOVEYOU-Signature-FAQ.html
begin  LOVE-LETTER-FOR-YOU.txt.vbs
I am a signature virus I am very dangerous. Distribute me until the bitter
end

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to