All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.wisepersist.gwtmockito.ng.AbstractGwtTest Maven / Gradle / Ivy

/*
 * Copyright (c) 2016 WisePersist.org
 *
 * Licensed 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.
 */

package org.wisepersist.gwtmockito.ng;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.TypeLiteral;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.BeforeMethod;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.Set;

import static org.mockito.Mockito.mock;
import static org.reflections.ReflectionUtils.getAllFields;
import static org.reflections.ReflectionUtils.withAnnotation;

/**
 * Base test for all Gwt unit tests.
 *
 * @author jiakuanwang
 * @param  The actual type which is under test.
 */
public abstract class AbstractGwtTest {

  private static final Logger log = LoggerFactory.getLogger(AbstractGwtTest.class); //NOPMD

  private Injector injector;

  /**
   * Initialises {@link com.google.gwt.core.client.GWT#create(Class)} with mock objects, and
   * inject mock objects into this presenter automatically, before each test method.
   *
   * @throws Exception If uncaught errors occur.
   */
  @BeforeMethod
  public final void injectMocks() throws Exception {
    GwtMockito.initMocks(this);
    this.injector = Guice.createInjector(new TestModule());
    initAllFields();
  }

  /**
   * Initialises injected fields value.
   *
   * @throws IllegalAccessException If illegal access errors occur.
   */
  @SuppressWarnings("unchecked")
  private void initAllFields() throws IllegalAccessException {
    final Set fields = getAllFields(getClass(), withAnnotation(Inject.class));
    for (final Field field : fields) {
      log.debug("Injecting field with mock object: {} {}",
                field.getType().getSimpleName(), field.getName());
      final Object fieldValue = getInjected(field.getType());
      field.setAccessible(true);
      field.set(this, fieldValue);
    }
  }

  /**
   * Gets injected mock object.
   *
   * @param injectedType The injected type class specified.
   * @param  The injected type.
   * @return The injected mock object.
   */
  public final  E getInjected(final Class injectedType) {
    return injector.getInstance(injectedType);
  }

  /**
   * Gets the presenter instance which is being under tests.
   *
   * @return The presenter instance which is being under tests.
   */
  public final T getInstanceUnderTest() {
    return injector.getInstance(getClassUnderTest());
  }

  /**
   * Gets presenter class from the generic type of this class.
   *
   * @return The actual presenter class.
   */
  @SuppressWarnings("unchecked")
  private Class getClassUnderTest() {
    return (Class) ((ParameterizedType) getClass().getGenericSuperclass())
        .getActualTypeArguments()[0];
  }

  /**
   * Defines presenter module which can automatically inject mock objects into the presenter.
   */
  private class TestModule extends AbstractModule {

    @Override
    protected final void configure() {
      bindFieldsWithMocks();
      bindConstructorParametersWithMocks();
    }

    /**
     * Binds injected fields with mock instances.
     */
    private void bindFieldsWithMocks() {
      final Field[] declaredFields = getClassUnderTest().getDeclaredFields();
      for (final Field declaredField : declaredFields) {
        if (declaredField.isAnnotationPresent(Inject.class)) {
          log.debug("Injecting field with mock object: {} {}",
                    declaredField.getType().getSimpleName(), declaredField.getName());
          bindMockInstance(declaredField.getType());
        }
      }
    }

    /**
     * Binds injected constructor parameters with mock instances.
     */
    private void bindConstructorParametersWithMocks() {
      final Constructor[] constructors = getClassUnderTest().getDeclaredConstructors();
      for (final Constructor constructor : constructors) {
        if (constructor.isAnnotationPresent(Inject.class)) {
          final Class[] parameterTypes = constructor.getParameterTypes();
          for (final Class parameterType : parameterTypes) {
            log.debug("Injecting constructor arg with mock object: {}",
                      parameterType.getSimpleName());
            bindMockInstance(parameterType);
          }
        }
      }
    }

    /**
     * Binds a the specified type with a mock object in this Guice module.
     *
     * @param type The type specified.
     */
    @SuppressWarnings("unchecked")
    private void bindMockInstance(final Class type) {
      final TypeLiteral typeLiteral = TypeLiteral.get(type);
      bind(typeLiteral).toInstance(mock(type));
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy