You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@onami.apache.org by Simone Tripodi <si...@apache.org> on 2013/03/11 20:30:37 UTC
Re: svn commit: r1455170 - in /incubator/onami/trunk/test/src:
main/java/org/apache/onami/test/OnamiRunner.java main/java/org/apache/onami/test/OnamiSuite.java
test/java/org/apache/onami/test/OnamiSuiteTest.java
SUPER! :)
http://people.apache.org/~simonetripodi/
http://simonetripodi.livejournal.com/
http://twitter.com/simonetripodi
http://www.99soft.org/
On Mon, Mar 11, 2013 at 4:12 PM, <er...@apache.org> wrote:
> Author: eric
> Date: Mon Mar 11 15:12:05 2013
> New Revision: 1455170
>
> URL: http://svn.apache.org/r1455170
> Log:
> [ONAMI-101] Add support for OnamiSuite
>
> Added:
> incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiSuite.java
> incubator/onami/trunk/test/src/test/java/org/apache/onami/test/OnamiSuiteTest.java
> Modified:
> incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiRunner.java
>
> Modified: incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiRunner.java
> URL: http://svn.apache.org/viewvc/incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiRunner.java?rev=1455170&r1=1455169&r2=1455170&view=diff
> ==============================================================================
> --- incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiRunner.java (original)
> +++ incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiRunner.java Mon Mar 11 15:12:05 2013
> @@ -46,6 +46,7 @@ import org.apache.onami.test.reflection.
> import org.apache.onami.test.reflection.HandleException;
> import org.junit.runner.notification.RunNotifier;
> import org.junit.runners.BlockJUnit4ClassRunner;
> +import org.junit.runners.Suite;
> import org.junit.runners.model.FrameworkMethod;
> import org.junit.runners.model.InitializationError;
>
> @@ -170,6 +171,42 @@ public class OnamiRunner
> }
>
> /**
> + * OnamiRunner constructor to create the runner needed
> + * by the OnamiSuite class.
> + *
> + * @see org.junit.runner.RunWith
> + * @param suite The suite test case class to run.
> + * @param test The test case class to run.
> + * @throws org.junit.runners.model.InitializationError if any error occurs.
> + */
> + public OnamiRunner( Class<?> suite, Class<?> test )
> + throws InitializationError
> + {
> + super( test );
> +
> + try
> + {
> + if ( LOGGER.isLoggable( Level.FINER ) )
> + {
> + LOGGER.finer( "Inizializing injector for test class: " + test.getName() );
> + }
> +
> + this.allModules = inizializeInjector( suite, test );
> +
> + if ( LOGGER.isLoggable( Level.FINER ) )
> + {
> + LOGGER.finer( "done..." );
> + }
> + }
> + catch ( Exception e )
> + {
> + final List<Throwable> throwables = new LinkedList<Throwable>();
> + throwables.add( e );
> + throw new InitializationError( throwables );
> + }
> + }
> +
> + /**
> * {@inheritDoc}
> */
> public void run( final RunNotifier notifier )
> @@ -222,6 +259,7 @@ public class OnamiRunner
> * @return The instance of the test case.
> * @throws Exception when an error occurs.
> */
> + @Override
> protected Object createTest()
> throws Exception
> {
> @@ -244,6 +282,30 @@ public class OnamiRunner
> }
>
> /**
> + * This method collects modules from {@link GuiceModules}, {@link GuiceProvidedModules}, {@link Mock}
> + * and {@ OnamiSuite}.
> + *
> + * @param <T> whatever input type is accepted
> + * @param suite the input suite to be analyzed
> + * @param test the input class has to be analyzed
> + * @return a List of Guice Modules built after input class analysis.
> + * @throws IllegalAccessException when a n error occurs.
> + * @throws InstantiationException when a n error occurs.
> + * @throws HandleException when a n error occurs.
> + */
> + protected <T> List<Module> inizializeInjector( Class<?> suite, Class<T> test)
> + throws HandleException, InstantiationException, IllegalAccessException
> + {
> + final List<Module> modules = inizializeInjector(test);
> + Module m = visitClass( suite );
> + if ( m != null )
> + {
> + modules.add( m );
> + }
> + return modules;
> + }
> +
> + /**
> * This method collects modules from {@link GuiceModules}, {@link GuiceProvidedModules}, {@link Mock}.
> *
> * @param <T> whatever input type is accepted
>
> Added: incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiSuite.java
> URL: http://svn.apache.org/viewvc/incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiSuite.java?rev=1455170&view=auto
> ==============================================================================
> --- incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiSuite.java (added)
> +++ incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiSuite.java Mon Mar 11 15:12:05 2013
> @@ -0,0 +1,452 @@
> +package org.apache.onami.test;
> +
> +/*
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements. See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership. The ASF licenses this file
> + * to you under the Apache License, Version 2.0 (the
> + * "License"); you may not use this file except in compliance
> + * with the License. You may obtain a copy of the License at
> + *
> + * http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing,
> + * software distributed under the License is distributed on an
> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + * KIND, either express or implied. See the License for the
> + * specific language governing permissions and limitations
> + * under the License.
> + */
> +
> +import java.lang.reflect.Field;
> +import java.lang.reflect.Modifier;
> +import java.util.ArrayList;
> +import java.util.HashMap;
> +import java.util.LinkedList;
> +import java.util.List;
> +import java.util.Map;
> +import java.util.Map.Entry;
> +import java.util.logging.Level;
> +import java.util.logging.Logger;
> +
> +import org.apache.onami.test.annotation.GuiceModules;
> +import org.apache.onami.test.annotation.GuiceProvidedModules;
> +import org.apache.onami.test.annotation.Mock;
> +import org.apache.onami.test.annotation.MockFramework;
> +import org.apache.onami.test.annotation.MockType;
> +import org.apache.onami.test.handler.GuiceInjectableClassHandler;
> +import org.apache.onami.test.handler.GuiceModuleHandler;
> +import org.apache.onami.test.handler.GuiceProvidedModuleHandler;
> +import org.apache.onami.test.handler.MockFrameworkHandler;
> +import org.apache.onami.test.handler.MockHandler;
> +import org.apache.onami.test.mock.MockEngine;
> +import org.apache.onami.test.mock.guice.MockTypeListener;
> +import org.apache.onami.test.reflection.ClassVisitor;
> +import org.apache.onami.test.reflection.HandleException;
> +import org.junit.runner.Runner;
> +import org.junit.runner.notification.RunNotifier;
> +import org.junit.runners.Suite;
> +import org.junit.runners.model.InitializationError;
> +import org.junit.runners.model.RunnerBuilder;
> +
> +import com.google.inject.AbstractModule;
> +import com.google.inject.Guice;
> +import com.google.inject.Inject;
> +import com.google.inject.Injector;
> +import com.google.inject.Module;
> +import com.google.inject.matcher.Matchers;
> +import com.google.inject.util.Modules;
> +
> +/**
> + * <p>
> + * It's a {@link Suite} runner.
> + * </p>
> + * <p>
> + * This class creates a Google Guice {@link Injector} configured by {@link GuiceModules} annotation (only fr modules
> + * with default constructor) and {@link GuiceProvidedModules} annotation and {@link Mock}.
> + * </p>
> + * <p>
> + * <b>Example #1:</b> <br>
> + *
> + * <pre>
> + *
> + * @org.junit.runner.RunWith( OnamiSuite.class )
> + * @GuiceModules( SimpleModule.class )
> + * @SuiteClasses({ .class })
> + * public class AcmeTestCase
> + * {
> + *
> + * @GuiceProvidedModules
> + * static public Module getProperties()
> + * {
> + * ...
> + * return Modules.combine(new ComplexModule( loadProperies() ), ... );
> + * }
> + *
> + * </pre>
> + *
> + * </p>
> + * <p>
> + * <b>Example #2:</b> <br>
> + *
> + * <pre>
> + *
> + * @org.junit.runner.RunWith( OnamiSuite.class )
> + * public class AcmeTestCase
> + * extends com.google.inject.AbstractModule
> + * {
> + *
> + * public void configure()
> + * {
> + * // Configure your proper modules
> + * ...
> + * bind( Service.class ).annotatedWith( TestAnnotation.class ).to( ServiceTestImpl.class );
> + * ...
> + * }
> + *
> + * @Mock
> + * private AnotherService serviceMock;
> + *
> + * @Inject
> + * private Service serviceTest;
> + *
> + * @org.junit.Test
> + * public void test()
> + * {
> + * assertNotNull( serviceMock );
> + * assertNotNull( serviceTest );
> + * }
> + * </pre>
> + *
> + * </p>
> + *
> + * @see GuiceMockModule
> + */
> +public class OnamiSuite
> + extends Suite
> +{
> +
> + private static final Logger LOGGER = Logger.getLogger( OnamiSuite.class.getName() );
> +
> + private Injector injector;
> +
> + private final List<Module> allModules;
> +
> + private final Map<Field, Object> mocked = new HashMap<Field, Object>( 1 );
> +
> + private MockType mockFramework = MockType.EASY_MOCK;
> +
> + private static Class<?>[] getAnnotatedClasses(Class<?> klass) throws InitializationError {
> + SuiteClasses annotation= klass.getAnnotation(SuiteClasses.class);
> + if (annotation == null)
> + throw new InitializationError(String.format("class '%s' must have a SuiteClasses annotation", klass.getName()));
> + return annotation.value();
> + }
> +
> + /**
> + * OnamiRunner constructor to create the core JUnice class.
> + *
> + * @see org.junit.runner.RunWith
> + * @param klass The test case class to run.
> + * @throws org.junit.runners.model.InitializationError if any error occurs.
> + */
> + public OnamiSuite( Class<?> klass, RunnerBuilder builder )
> + throws InitializationError
> + {
> + this(builder, klass, getAnnotatedClasses(klass));
> +
> + }
> +
> + /**
> + * Called by this class and subclasses once the classes making up the suite have been determined
> + *
> + * @param builder builds runners for classes in the suite
> + * @param klass the root of the suite
> + * @param suiteClasses the classes in the suite
> + * @throws InitializationError
> + */
> + protected OnamiSuite( RunnerBuilder builder, Class<?> suite, Class<?>[] suiteClasses )
> + throws InitializationError
> + {
> + super( suite, runners( suite, suiteClasses ) );
> + try
> + {
> + if ( LOGGER.isLoggable( Level.FINER ) )
> + {
> + LOGGER.finer( "Inizializing injector for siote class: " + suite.getName() );
> + }
> +
> + this.allModules = inizializeInjector( suite );
> +
> + if ( LOGGER.isLoggable( Level.FINER ) )
> + {
> + LOGGER.finer( "done..." );
> + }
> + }
> + catch ( Exception e )
> + {
> + final List<Throwable> throwables = new LinkedList<Throwable>();
> + throwables.add( e );
> + throw new InitializationError( throwables );
> + }
> + }
> +
> + /**
> + * {@inheritDoc}
> + */
> + public void run( final RunNotifier notifier )
> + {
> + if ( LOGGER.isLoggable( Level.FINER ) )
> + {
> + LOGGER.finer( " ### Run test case: " + getTestClass().getJavaClass() + " ### " );
> + LOGGER.finer( " #### Creating injector ####" );
> + }
> +
> + this.injector = createInjector( allModules );
> + super.run( notifier );
> + this.flush();
> +
> + if ( LOGGER.isLoggable( Level.FINER ) )
> + {
> + LOGGER.finer( " ### End test case: " + getTestClass().getJavaClass().getName() + " ### " );
> + }
> + }
> +
> + private static List<Runner> runners( Class<?> suite, Class<?>[] children ) throws InitializationError {
> + ArrayList<Runner> runners= new ArrayList<Runner>();
> + for (Class<?> each : children) {
> + Runner childRunner= new OnamiRunner( suite, each );
> + if (childRunner != null)
> + runners.add(childRunner);
> + }
> + return runners;
> + }
> +
> + /**
> + * {@inheritDoc}
> + */
> + private void flush()
> + {
> + this.injector = null;
> + this.allModules.clear();
> + this.mocked.clear();
> + }
> +
> + @Override
> + protected void runChild( Runner runner, RunNotifier notifier )
> + {
> + if ( LOGGER.isLoggable( Level.FINER ) )
> + {
> + LOGGER.finer( " +++ invoke runner: " + runner + " +++ " );
> + }
> +
> + super.runChild( runner, notifier );
> + resetAllResetAfterMocks();
> +
> + if ( LOGGER.isLoggable( Level.FINER ) )
> + {
> + LOGGER.finer( " --- end runner: " + runner + " --- " );
> + }
> + }
> +
> + /**
> + * Shortcut to create the Injector given a list of Modules.
> + *
> + * @param modules the list of modules have to be load
> + * @return an Injector instance built using the input Module list
> + */
> + protected Injector createInjector( List<Module> modules )
> + {
> + return Guice.createInjector( modules );
> + }
> +
> + /**
> + * This method collects modules from {@link GuiceModules}, {@link GuiceProvidedModules}, {@link Mock}.
> + *
> + * @param <T> whatever input type is accepted
> + * @param clazz the input class has to be analyzed
> + * @return a List of Guice Modules built after input class analysis.
> + * @throws IllegalAccessException when a n error occurs.
> + * @throws InstantiationException when a n error occurs.
> + * @throws HandleException when a n error occurs.
> + */
> + protected <T> List<Module> inizializeInjector( Class<T> clazz )
> + throws HandleException, InstantiationException, IllegalAccessException
> + {
> + final List<Module> modules = new ArrayList<Module>();
> + Module m = visitClass( clazz );
> + if ( m != null )
> + {
> + modules.add( m );
> + }
> + return modules;
> + }
> +
> + private void resetAllResetAfterMocks()
> + {
> + for ( Entry<Field, Object> entry : mocked.entrySet() )
> + {
> + final Mock mockAnnotation = entry.getKey().getAnnotation( Mock.class );
> + if ( mockAnnotation.resetAfter() )
> + {
> + MockEngine mockEngine = MockEngineFactory.getMockEngine( mockFramework );
> + mockEngine.resetMock( entry.getValue() );
> + }
> + }
> + }
> +
> + /**
> + * @throws HandleException
> + * @throws IllegalAccessException
> + * @throws InstantiationException
> + */
> + private <T> Module visitClass( final Class<T> clazz )
> + throws HandleException, InstantiationException, IllegalAccessException
> + {
> + try
> + {
> + if ( LOGGER.isLoggable( Level.FINER ) )
> + {
> + LOGGER.finer( " Start introspecting class: " + clazz.getName() );
> + }
> + final List<Module> allModules = new ArrayList<Module>();
> +
> + // Setup the handlers
> + final GuiceProvidedModuleHandler guiceProvidedModuleHandler = new GuiceProvidedModuleHandler();
> + final GuiceModuleHandler guiceModuleHandler = new GuiceModuleHandler();
> + final GuiceInjectableClassHandler<Inject> guiceInjectableClassHandler = new GuiceInjectableClassHandler<Inject>();
> + final GuiceInjectableClassHandler<javax.inject.Inject> jsr330InjectableClassHandler = new GuiceInjectableClassHandler<javax.inject.Inject>();
> +
> + final MockHandler mockHandler = new MockHandler();
> + final MockFrameworkHandler mockFrameworkHandler = new MockFrameworkHandler();
> +
> + // Visit class and super-classes
> + new ClassVisitor()
> + .registerHandler( GuiceProvidedModules.class, guiceProvidedModuleHandler )
> + .registerHandler( GuiceModules.class, guiceModuleHandler )
> + .registerHandler( Mock.class, mockHandler )
> + .registerHandler( MockFramework.class, mockFrameworkHandler )
> + .registerHandler( Inject.class, guiceInjectableClassHandler )
> + .registerHandler( javax.inject.Inject.class, jsr330InjectableClassHandler )
> + .visit( clazz );
> +
> + // Retrieve mock framework
> + if ( mockFrameworkHandler.getMockType() != null )
> + {
> + this.mockFramework = mockFrameworkHandler.getMockType();
> + }
> +
> + // retrieve the modules founded
> + allModules.addAll( guiceProvidedModuleHandler.getModules() );
> + allModules.addAll( guiceModuleHandler.getModules() );
> + MockEngine engine = MockEngineFactory.getMockEngine( this.mockFramework );
> + this.mocked.putAll( mockHandler.getMockedObject( engine ) );
> + if ( !this.mocked.isEmpty() )
> + {
> + // Replace all real module binding with Mocked moduled.
> + Module m = Modules.override( allModules ).with( new GuiceMockModule( this.mocked ) );
> + allModules.clear();
> + allModules.add( m );
> + }
> +
> + // Add only clasess that have got the Inject annotation
> + final Class<?>[] guiceInjectableClasses = guiceInjectableClassHandler.getClasses();
> + final Class<?>[] jsr330InjectableClasses = jsr330InjectableClassHandler.getClasses();
> +
> + final AbstractModule statcInjector = new AbstractModule()
> + {
> + @Override
> + protected void configure()
> + {
> + // inject all STATIC dependencies
> + if ( guiceInjectableClasses.length != 0 )
> + {
> + requestStaticInjection( guiceInjectableClasses );
> + }
> +
> + if ( jsr330InjectableClasses.length != 0 )
> + {
> + requestStaticInjection( jsr330InjectableClasses );
> + }
> +
> +
> + }
> + };
> + if ( guiceInjectableClasses.length != 0 || jsr330InjectableClasses.length != 0 )
> + {
> + allModules.add( statcInjector );
> + }
> +
> + // Check if the class is itself a Google Module.
> + if ( Module.class.isAssignableFrom( getTestClass().getJavaClass() ) )
> + {
> + if ( LOGGER.isLoggable( Level.FINER ) )
> + {
> + LOGGER.finer( " creating module from test class " + getTestClass().getJavaClass() );
> + }
> + final Module classModule = (Module) getTestClass().getJavaClass().newInstance();
> + allModules.add( classModule );
> + }
> +
> + // create MockTypeListenerModule
> + if ( this.mocked.size() != 0 )
> + {
> + final AbstractModule mockTypeListenerModule = new AbstractModule()
> + {
> + @Override
> + protected void configure()
> + {
> + bindListener( Matchers.any(), new MockTypeListener( mocked ) );
> + }
> + };
> +
> + // BEGIN patch for issue: google-guice: #452
> + for ( Entry<Field, Object> entry : mocked.entrySet() )
> + {
> + final Field field = entry.getKey();
> + final Object mock = entry.getValue();
> + if ( Modifier.isStatic( field.getModifiers() ) )
> + {
> + if ( LOGGER.isLoggable( Level.FINER ) )
> + {
> + LOGGER.finer( " inject static mock field: " + field.getName() );
> + }
> +
> + field.setAccessible( true );
> + field.set( field.getDeclaringClass(), mock );
> + }
> + }
> + // END patch for issue: google-guice: #452
> +
> + allModules.add( mockTypeListenerModule );
> + }
> +
> + if ( allModules.size() != 0 )
> + {
> + if ( LOGGER.isLoggable( Level.FINER ) )
> + {
> + StringBuilder builder = new StringBuilder();
> + builder.append( " Collected modules: " );
> + builder.append( "\n" );
> + for ( Module module : allModules )
> + {
> + builder.append( " " + module );
> + builder.append( "\n" );
> + }
> + LOGGER.finer( builder.toString() );
> + }
> + return Modules.combine( allModules );
> + }
> + return null;
> + }
> + finally
> + {
> + if ( LOGGER.isLoggable( Level.FINER ) )
> + {
> + LOGGER.finer( " ...done" );
> + }
> + }
> + }
> +
> +}
>
> Added: incubator/onami/trunk/test/src/test/java/org/apache/onami/test/OnamiSuiteTest.java
> URL: http://svn.apache.org/viewvc/incubator/onami/trunk/test/src/test/java/org/apache/onami/test/OnamiSuiteTest.java?rev=1455170&view=auto
> ==============================================================================
> --- incubator/onami/trunk/test/src/test/java/org/apache/onami/test/OnamiSuiteTest.java (added)
> +++ incubator/onami/trunk/test/src/test/java/org/apache/onami/test/OnamiSuiteTest.java Mon Mar 11 15:12:05 2013
> @@ -0,0 +1,10 @@
> +package org.apache.onami.test;
> +
> +import org.junit.runner.RunWith;
> +import org.junit.runners.Suite.SuiteClasses;
> +
> +@RunWith(OnamiSuite.class)
> +@SuiteClasses({ InjectDependingMockObjectTestCase.class, InjectFromSuperClassTestCase.class })
> +public class OnamiSuiteTest {
> +
> +}
>
>