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>
> + *
> + * &#064;org.junit.runner.RunWith( OnamiSuite.class )
> + * &#064;GuiceModules( SimpleModule.class )
> + * &#064;SuiteClasses({ .class })
> + * public class AcmeTestCase
> + * {
> + *
> + *     &#064;GuiceProvidedModules
> + *     static public Module getProperties()
> + *     {
> + *         ...
> + *         return Modules.combine(new ComplexModule( loadProperies() ), ...  );
> + *     }
> + *
> + * </pre>
> + *
> + * </p>
> + * <p>
> + * <b>Example #2:</b> <br>
> + *
> + * <pre>
> + *
> + * &#064;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 );
> + *         ...
> + *     }
> + *
> + *     &#064;Mock
> + *     private AnotherService serviceMock;
> + *
> + *     &#064;Inject
> + *     private Service serviceTest;
> + *
> + *     &#064;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 {
> +
> +}
>
>