org.skyscreamer
jsonassert
diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/AutoConfigureTestDatabase.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/AutoConfigureTestDatabase.java
new file mode 100644
index 0000000000..51ab895eee
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/AutoConfigureTestDatabase.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * 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.springframework.boot.test.autoconfigure.orm.jpa;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.sql.DataSource;
+
+import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
+import org.springframework.boot.autoconfigure.jdbc.EmbeddedDatabaseConnection;
+import org.springframework.boot.test.autoconfigure.properties.PropertyMapping;
+
+/**
+ * Annotation that can be applied to a test class to configure a test database to use
+ * instead of any application defined or auto-configured {@link DataSource}.
+ *
+ * @author Phillip Webb
+ * @see TestDatabaseAutoConfiguration
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@ImportAutoConfiguration(TestDatabaseAutoConfiguration.class)
+@PropertyMapping("spring.test.database")
+public @interface AutoConfigureTestDatabase {
+
+ /**
+ * If the test database should replace any existing.
+ */
+ Replace replace() default Replace.ANY;
+
+ /**
+ * The type of connection to be establish when {@link #replace() replacing} the data
+ * source. By default will attempt to detect the connection based on the classpath.
+ */
+ EmbeddedDatabaseConnection connection() default EmbeddedDatabaseConnection.NONE;
+
+ /**
+ * What the test database can replace.
+ */
+ enum Replace {
+
+ /**
+ * Replace any DataSource bean (auto-configured or manually defined).
+ */
+ ANY,
+
+ /**
+ * Only replace auto-configured DataSource.
+ */
+ AUTO_CONFIGURED,
+
+ /**
+ * Don't replace the application default DataSource.
+ */
+ NONE
+
+ }
+
+}
diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/AutoConfigureTestEntityManager.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/AutoConfigureTestEntityManager.java
new file mode 100644
index 0000000000..247567751c
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/AutoConfigureTestEntityManager.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * 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.springframework.boot.test.autoconfigure.orm.jpa;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
+
+/**
+ * Annotation that can be applied to a test class to enable and configure
+ * auto-configuration of a {@link TestEntityManager}.
+ *
+ * @author Phillip Webb
+ * @see TestEntityManagerAutoConfiguration
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@ImportAutoConfiguration(TestEntityManagerAutoConfiguration.class)
+public @interface AutoConfigureTestEntityManager {
+
+}
diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java
new file mode 100644
index 0000000000..3fa3466656
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * 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.springframework.boot.test.autoconfigure.orm.jpa;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.filter.TypeExcludeFilters;
+import org.springframework.boot.test.autoconfigure.properties.PropertyMapping;
+import org.springframework.boot.test.context.SpringApplicationTest;
+import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
+import org.springframework.context.annotation.ComponentScan.Filter;
+import org.springframework.test.context.BootstrapWith;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Annotation that can be used in combination with {@code @RunWith(SpringRunner.class)}
+ * for a typical JPA test. Can be used when a test focuses only on JPA
+ * components.
+ *
+ * Using this annotation will disable full auto-configuration and instead apply only
+ * configuration relevant to JPA tests.
+ *
+ * By default, tests annotated with {@code @DataJpaTest} will use an embedded in-memory
+ * database (replacing any explicit or usually auto-configured DataSource). The
+ * {@link AutoConfigureTestDatabase @AutoConfigureTestDatabase} annotation can be used to
+ * override these settings.
+ *
+ * If you are looking to load your full application configuration, but use an embedded
+ * database, you should consider {@link SpringApplicationTest @SpringApplicationTest}
+ * combined with {@link AutoConfigureTestDatabase @AutoConfigureTestDatabase} rather than
+ * this annotation.
+ *
+ * @author Phillip Webb
+ * @see AutoConfigureTestDatabase
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+@BootstrapWith(SpringBootTestContextBootstrapper.class)
+@OverrideAutoConfiguration(enabled = false)
+@TypeExcludeFilters(DataJpaTypeExcludeFilter.class)
+@Transactional
+@ImportDataJpaAutoConfiguration
+@AutoConfigureTestDatabase
+@AutoConfigureTestEntityManager
+public @interface DataJpaTest {
+
+ /**
+ * If SQL output should be logged.
+ */
+ @PropertyMapping("spring.jpa.show-sql")
+ boolean showSql() default true;
+
+ /**
+ * Determines if default filtering should be used with
+ * {@link SpringBootApplication @SpringBootApplication}. By default no beans are
+ * included.
+ * @see #includeFilters()
+ * @see #excludeFilters()
+ */
+ boolean useDefaultFilters() default true;
+
+ /**
+ * A set of include filters which can be used to add otherwise filtered beans to the
+ * application context.
+ */
+ Filter[] includeFilters() default {};
+
+ /**
+ * A set of exclude filters which can be used to filter beans that would otherwise be
+ * added to the application context.
+ */
+ Filter[] excludeFilters() default {};
+
+}
diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTypeExcludeFilter.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTypeExcludeFilter.java
new file mode 100644
index 0000000000..cc8063654b
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTypeExcludeFilter.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * 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.springframework.boot.test.autoconfigure.orm.jpa;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Set;
+
+import org.springframework.boot.context.TypeExcludeFilter;
+import org.springframework.boot.test.autoconfigure.filter.AnnotationCustomizableTypeExcludeFilter;
+import org.springframework.context.annotation.ComponentScan.Filter;
+import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
+
+/**
+ * {@link TypeExcludeFilter} for {@link DataJpaTest @DataJpaTest}.
+ *
+ * @author Phillip Webb
+ */
+class DataJpaTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter {
+
+ private final DataJpaTest annotation;
+
+ DataJpaTypeExcludeFilter(Class> testClass) {
+ this.annotation = AnnotatedElementUtils.getMergedAnnotation(testClass,
+ DataJpaTest.class);
+ }
+
+ @Override
+ protected boolean hasAnnotation() {
+ return this.annotation != null;
+ }
+
+ @Override
+ protected Filter[] getFilters(FilterType type) {
+ switch (type) {
+ case INCLUDE:
+ return this.annotation.includeFilters();
+ case EXCLUDE:
+ return this.annotation.excludeFilters();
+ }
+ throw new IllegalStateException("Unsupported type " + type);
+ }
+
+ @Override
+ protected boolean isUseDefaultFilters() {
+ return this.annotation.useDefaultFilters();
+ }
+
+ @Override
+ protected boolean defaultInclude(MetadataReader metadataReader,
+ MetadataReaderFactory metadataReaderFactory) throws IOException {
+ return false;
+ }
+
+ @Override
+ protected Set> getDefaultIncudes() {
+ return Collections.emptySet();
+ }
+
+}
diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/ImportDataJpaAutoConfiguration.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/ImportDataJpaAutoConfiguration.java
new file mode 100644
index 0000000000..05de6d222a
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/ImportDataJpaAutoConfiguration.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * 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.springframework.boot.test.autoconfigure.orm.jpa;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
+import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
+import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
+import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration;
+
+/**
+ * {@link ImportAutoConfiguration Auto-configuration imports} for typical Data JPA tests.
+ * Most tests should consider using {@link DataJpaTest @DataJpaTest} rather than using
+ * this annotation directly.
+ *
+ * @author Phillip Webb
+ * @since 1.4.0
+ * @see DataJpaTest
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@ImportAutoConfiguration({ HibernateJpaAutoConfiguration.class,
+ JpaRepositoriesAutoConfiguration.class, TransactionAutoConfiguration.class,
+ DataSourceTransactionManagerAutoConfiguration.class,
+ DataSourceAutoConfiguration.class })
+public @interface ImportDataJpaAutoConfiguration {
+
+}
diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestDatabaseAutoConfiguration.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestDatabaseAutoConfiguration.java
new file mode 100644
index 0000000000..2ff86acdeb
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestDatabaseAutoConfiguration.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * 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.springframework.boot.test.autoconfigure.orm.jpa;
+
+import javax.sql.DataSource;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.autoconfigure.jdbc.EmbeddedDatabaseConnection;
+import org.springframework.context.EnvironmentAware;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.core.env.Environment;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
+import org.springframework.util.Assert;
+import org.springframework.util.ObjectUtils;
+
+/**
+ * Auto-configuration for a test database.
+ *
+ * @author Phillip Webb
+ * @see AutoConfigureTestDatabase
+ */
+@Configuration
+@AutoConfigureBefore(DataSourceAutoConfiguration.class)
+class TestDatabaseAutoConfiguration {
+
+ private final Environment environment;
+
+ TestDatabaseAutoConfiguration(Environment environment) {
+ this.environment = environment;
+ }
+
+ @Bean
+ @ConditionalOnProperty(prefix = "spring.test.database", name = "replace", havingValue = "AUTO_CONFIGURED")
+ @ConditionalOnMissingBean
+ public DataSource dataSource() {
+ return new EmbeddedDataSourceFactory(this.environment).getEmbeddedDatabase();
+ }
+
+ @Bean
+ @ConditionalOnProperty(prefix = "spring.test.database", name = "replace", havingValue = "ANY", matchIfMissing = true)
+ public static EmbeddedDataSourceBeanFactoryPostProcessor embeddedDataSourceBeanFactoryPostProcessor() {
+ return new EmbeddedDataSourceBeanFactoryPostProcessor();
+ }
+
+ @Order(Ordered.LOWEST_PRECEDENCE)
+ private static class EmbeddedDataSourceBeanFactoryPostProcessor
+ implements BeanDefinitionRegistryPostProcessor {
+
+ private static final Log logger = LogFactory
+ .getLog(EmbeddedDataSourceBeanFactoryPostProcessor.class);
+
+ @Override
+ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
+ throws BeansException {
+ Assert.isInstanceOf(ConfigurableListableBeanFactory.class, registry,
+ "Test Database Auto-configuration can only be "
+ + "used with a ConfigurableListableBeanFactory");
+ process(registry, (ConfigurableListableBeanFactory) registry);
+ }
+
+ @Override
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
+ throws BeansException {
+ }
+
+ private void process(BeanDefinitionRegistry registry,
+ ConfigurableListableBeanFactory beanFactory) {
+ BeanDefinitionHolder holder = getDataSourceBeanDefinition(beanFactory);
+ logger.info("Replacing '" + holder.getBeanName()
+ + "' DataSource bean with embedded version");
+ registry.registerBeanDefinition(holder.getBeanName(),
+ createEmbeddedBeanDefinition());
+ }
+
+ private BeanDefinition createEmbeddedBeanDefinition() {
+ return new RootBeanDefinition(EmbeddedDataSourceFactoryBean.class);
+ }
+
+ private BeanDefinitionHolder getDataSourceBeanDefinition(
+ ConfigurableListableBeanFactory beanFactory) {
+ String[] beanNames = beanFactory.getBeanNamesForType(DataSource.class);
+ if (!ObjectUtils.isEmpty(beanNames)) {
+ if (beanNames.length == 1) {
+ String beanName = beanNames[0];
+ BeanDefinition beanDefinition = beanFactory
+ .getBeanDefinition(beanName);
+ return new BeanDefinitionHolder(beanDefinition, beanName);
+ }
+ for (String beanName : beanNames) {
+ BeanDefinition beanDefinition = beanFactory
+ .getBeanDefinition(beanName);
+ if (beanDefinition.isPrimary()) {
+ return new BeanDefinitionHolder(beanDefinition, beanName);
+ }
+ logger.warn("No primary DataSource found, "
+ + "embedded version will not be used");
+ }
+
+ }
+ return null;
+ }
+
+ }
+
+ private static class EmbeddedDataSourceFactoryBean
+ implements FactoryBean, EnvironmentAware, InitializingBean {
+
+ private EmbeddedDataSourceFactory factory;
+
+ private EmbeddedDatabase embeddedDatabase;
+
+ @Override
+ public void setEnvironment(Environment environment) {
+ this.factory = new EmbeddedDataSourceFactory(environment);
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ this.embeddedDatabase = this.factory.getEmbeddedDatabase();
+ }
+
+ @Override
+ public DataSource getObject() throws Exception {
+ return this.embeddedDatabase;
+ }
+
+ @Override
+ public Class> getObjectType() {
+ return EmbeddedDatabase.class;
+ }
+
+ @Override
+ public boolean isSingleton() {
+ return true;
+ }
+
+ }
+
+ private static class EmbeddedDataSourceFactory {
+
+ private final Environment environment;
+
+ EmbeddedDataSourceFactory(Environment environment) {
+ this.environment = environment;
+ }
+
+ public EmbeddedDatabase getEmbeddedDatabase() {
+ EmbeddedDatabaseConnection connection = this.environment.getProperty(
+ "spring.test.database.connection", EmbeddedDatabaseConnection.class,
+ EmbeddedDatabaseConnection.NONE);
+ if (EmbeddedDatabaseConnection.NONE.equals(connection)) {
+ connection = EmbeddedDatabaseConnection.get(getClass().getClassLoader());
+ }
+ return new EmbeddedDatabaseBuilder().setType(connection.getType()).build();
+ }
+
+ }
+
+}
diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestEntityManager.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestEntityManager.java
new file mode 100644
index 0000000000..5bb62ab7a1
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestEntityManager.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * 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.springframework.boot.test.autoconfigure.orm.jpa;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceUnitUtil;
+
+import org.springframework.orm.jpa.EntityManagerFactoryUtils;
+import org.springframework.util.Assert;
+
+/**
+ * Alternative to {@link EntityManager} for use in JPA tests. Provides a subset of
+ * {@link EntityManager} methods that are useful for tests as well as helper methods for
+ * common testing tasks such as {@link #persistFlushFind(Object) persist/flush/find}.
+ *
+ * @author Phillip Webb
+ * @since 1.4.0
+ */
+public class TestEntityManager {
+
+ private final EntityManagerFactory entityManagerFactory;
+
+ /**
+ * Create a new {@link TestEntityManager} instance for the given
+ * {@link EntityManagerFactory}.
+ * @param entityManagerFactory the source entity manager factory
+ */
+ public TestEntityManager(EntityManagerFactory entityManagerFactory) {
+ Assert.notNull(entityManagerFactory, "EntityManagerFactory must not be null");
+ this.entityManagerFactory = entityManagerFactory;
+ }
+
+ /**
+ * Make an instance managed and persistent then return it's ID. Delegates to
+ * {@link EntityManager#persist(Object)} then {@link #getId(Object)}.
+ *
+ * Helpful when setting up test data in a test:
+ * Object entityId = this.testEntityManager.persist(new MyEntity("Spring"));
+ *
+ * @param entity the source entity
+ * @return the ID of the newly persisted entity
+ */
+ public Object persistAndGetId(Object entity) {
+ persist(entity);
+ return getId(entity);
+ }
+
+ /**
+ * Make an instance managed and persistent then return it's ID. Delegates to
+ * {@link EntityManager#persist(Object)} then {@link #getId(Object, Class)}.
+ *
+ * Helpful when setting up test data in a test:
+ * Long entityId = this.testEntityManager.persist(new MyEntity("Spring"), Long.class);
+ *
+ * @param the ID type
+ * @param entity the source entity
+ * @param idType the ID type
+ * @return the ID of the newly persisted entity
+ */
+ public T persistAndGetId(Object entity, Class idType) {
+ persist(entity);
+ return getId(entity, idType);
+
+ }
+
+ /**
+ * Make an instance managed and persistent. Delegates to
+ * {@link EntityManager#persist(Object)} then returns the original source entity.
+ *
+ * Helpful when setting up test data in a test:
+ * MyEntity entity = this.testEntityManager.persist(new MyEntity("Spring"));
+ *
+ * @param the entity type
+ * @param entity the entity to persist
+ * @return the persisted entity
+ */
+ public E persist(E entity) {
+ Assert.state(getId(entity) == null,
+ "Entity " + entity.getClass().getName() + " already has an ID");
+ getEntityManager().persist(entity);
+ return entity;
+ }
+
+ /**
+ * Make an instance managed and persistent, synchronize the persistence context to the
+ * underlying database and finally find the persisted entity by its ID. Delegates to
+ * {@link #persistAndFlush(Object)} then {@link #find(Class, Object)} with the
+ * {@link #getId(Object) entity ID}.
+ *
+ * Helpful when ensuring that entity data is actually written and read from the
+ * underling database correctly.
+ * @param the entity type
+ * @param entity the entity to persist
+ * @return the entity found using the ID of the persisted entity
+ */
+ @SuppressWarnings("unchecked")
+ public E persistFlushFind(E entity) {
+ EntityManager entityManager = getEntityManager();
+ persistAndFlush(entity);
+ Object id = getId(entity);
+ entityManager.detach(entity);
+ return (E) entityManager.find(entity.getClass(), id);
+ }
+
+ /**
+ * Make an instance managed and persistent then synchronize the persistence context to
+ * the underlying database. Delegates to {@link EntityManager#persist(Object)} then
+ * {@link #flush()} and finally returns the original source entity.
+ *
+ * Helpful when setting up test data in a test:
+ * MyEntity entity = this.testEntityManager.persistAndFlush(new MyEntity("Spring"));
+ *
+ * @param the entity type
+ * @param entity the entity to persist
+ * @return the persisted entity
+ */
+ public E persistAndFlush(E entity) {
+ persist(entity);
+ flush();
+ return entity;
+ }
+
+ /**
+ * Merge the state of the given entity into the current persistence context. Delegates
+ * to {@link EntityManager#merge(Object)}
+ * @param the entity type
+ * @param entity the entity to merge
+ * @return the merged entity
+ */
+ public E merge(E entity) {
+ return getEntityManager().merge(entity);
+ }
+
+ /**
+ * Remove the entity instance. Delegates to {@link EntityManager#remove(Object)}
+ * @param entity the entity to remove
+ */
+ public void remove(Object entity) {
+ getEntityManager().remove(entity);
+ }
+
+ /**
+ * Find by primary key. Delegates to {@link EntityManager#find(Class, Object)}.
+ * @param the entity type
+ * @param entityClass the entity class
+ * @param primaryKey the entity primary key
+ * @return the found entity or {@code null} if the entity does not exist
+ * @see #getId(Object)
+ */
+ public E find(Class entityClass, Object primaryKey) {
+ return getEntityManager().find(entityClass, primaryKey);
+ }
+
+ /**
+ * Synchronize the persistence context to the underlying database. Delegates to
+ * {@link EntityManager#flush()}.
+ */
+ public void flush() {
+ getEntityManager().flush();
+ }
+
+ /**
+ * Refresh the state of the instance from the database, overwriting changes made to
+ * the entity, if any. Delegates to {@link EntityManager#refresh(Object)}.
+ * @param the entity type
+ * @param entity the entity to refresh
+ * @return the refreshed entity
+ */
+ public E refresh(E entity) {
+ getEntityManager().refresh(entity);
+ return entity;
+ }
+
+ /**
+ * Clear the persistence context, causing all managed entities to become detached.
+ * Delegates to {@link EntityManager#clear()}
+ */
+ public void clear() {
+ getEntityManager().clear();
+ }
+
+ /**
+ * Remove the given entity from the persistence context, causing a managed entity to
+ * become detached. Delegates to {@link EntityManager#detach(Object)}.
+ * @param entity the entity to detach.
+ */
+ public void detach(Object entity) {
+ getEntityManager().detach(entity);
+ }
+
+ /**
+ * Return the ID of the given entity. Delegates to
+ * {@link PersistenceUnitUtil#getIdentifier(Object)}.
+ * @param entity the source entity
+ * @return the ID of the entity or {@code null}
+ * @see #getId(Object, Class)
+ */
+ public Object getId(Object entity) {
+ return this.entityManagerFactory.getPersistenceUnitUtil().getIdentifier(entity);
+ }
+
+ /**
+ * Return the ID of the given entity cast to a specific type. Delegates to
+ * {@link PersistenceUnitUtil#getIdentifier(Object)}.
+ * @param the ID type
+ * @param entity the source entity
+ * @param idType the expected ID type
+ * @return the ID of the entity or {@code null}
+ * @see #getId(Object)
+ */
+ @SuppressWarnings("unchecked")
+ public T getId(Object entity, Class idType) {
+ Object id = getId(entity);
+ Assert.isInstanceOf(idType, id, "ID missmatch");
+ return (T) id;
+ }
+
+ /**
+ * Return the underlying {@link EntityManager} that's actually used to perform all
+ * operations.
+ * @return the entity manager
+ */
+ public final EntityManager getEntityManager() {
+ EntityManager manager = EntityManagerFactoryUtils
+ .getTransactionalEntityManager(this.entityManagerFactory);
+ Assert.state(manager != null, "No transactional EnitiyManager found");
+ return manager;
+ }
+
+}
diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestEntityManagerAutoConfiguration.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestEntityManagerAutoConfiguration.java
new file mode 100644
index 0000000000..756dfea256
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestEntityManagerAutoConfiguration.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * 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.springframework.boot.test.autoconfigure.orm.jpa;
+
+import javax.persistence.EntityManagerFactory;
+
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Auto-configuration for {@link TestEntityManager}.
+ *
+ * @author Phillip Webb
+ * @see AutoConfigureTestEntityManager
+ */
+@Configuration
+@ConditionalOnClass({ EntityManagerFactory.class })
+@AutoConfigureAfter(HibernateJpaAutoConfiguration.class)
+class TestEntityManagerAutoConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ public TestEntityManager testEntityManager(
+ EntityManagerFactory entityManagerFactory) {
+ return new TestEntityManager(entityManagerFactory);
+ }
+
+}
diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/package-info.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/package-info.java
new file mode 100644
index 0000000000..f1121a689d
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * 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.
+ */
+
+/**
+ * Auto-configuration for Data JPA tests.
+ */
+package org.springframework.boot.test.autoconfigure.orm.jpa;
diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestIntegrationTests.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestIntegrationTests.java
new file mode 100644
index 0000000000..658ac5e206
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestIntegrationTests.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * 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.springframework.boot.test.autoconfigure.orm.jpa;
+
+import javax.sql.DataSource;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Integration tests for {@link DataJpaTest}.
+ *
+ * @author Phillip Webb
+ */
+@RunWith(SpringRunner.class)
+@DataJpaTest
+public class DataJpaTestIntegrationTests {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Autowired
+ private TestEntityManager entities;
+
+ @Autowired
+ private ExampleRepository repository;
+
+ @Autowired
+ private DataSource dataSource;
+
+ @Autowired
+ private ApplicationContext applicationContext;
+
+ @Test
+ public void testEntityManager() throws Exception {
+ ExampleEntity entity = this.entities.persist(new ExampleEntity("spring", "123"));
+ this.entities.flush();
+ Object id = this.entities.getId(entity);
+ ExampleEntity found = this.entities.find(ExampleEntity.class, id);
+ assertThat(found.getName()).isEqualTo("spring");
+ }
+
+ @Test
+ public void testEntityManagerPersistAndGetId() throws Exception {
+ Long id = this.entities.persistAndGetId(new ExampleEntity("spring", "123"),
+ Long.class);
+ assertThat(id).isNotNull();
+ }
+
+ @Test
+ public void testRepository() throws Exception {
+ this.entities.persist(new ExampleEntity("spring", "123"));
+ this.entities.persist(new ExampleEntity("boot", "124"));
+ this.entities.flush();
+ ExampleEntity found = this.repository.findByReference("124");
+ assertThat(found.getName()).isEqualTo("boot");
+ }
+
+ @Test
+ public void replacesDefinedDatasourceWithEmbeddedDefault() throws Exception {
+ String product = this.dataSource.getConnection().getMetaData()
+ .getDatabaseProductName();
+ assertThat(product).isEqualTo("H2");
+ }
+
+ @Test
+ public void didNotInjectExampleComponent() throws Exception {
+ this.thrown.expect(NoSuchBeanDefinitionException.class);
+ this.applicationContext.getBean(ExampleComponent.class);
+ }
+
+}
diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestWithAutoConfigureTestDatabaseReplaceAutoConfiguredIntegrationTests.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestWithAutoConfigureTestDatabaseReplaceAutoConfiguredIntegrationTests.java
new file mode 100644
index 0000000000..028a844325
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestWithAutoConfigureTestDatabaseReplaceAutoConfiguredIntegrationTests.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * 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.springframework.boot.test.autoconfigure.orm.jpa;
+
+import javax.sql.DataSource;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.jdbc.EmbeddedDatabaseConnection;
+import org.springframework.boot.test.autoconfigure.orm.jpa.AutoConfigureTestDatabase.Replace;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Integration tests for {@link DataJpaTest}.
+ *
+ * @author Phillip Webb
+ */
+@RunWith(SpringRunner.class)
+@DataJpaTest
+@AutoConfigureTestDatabase(replace = Replace.AUTO_CONFIGURED, connection = EmbeddedDatabaseConnection.HSQL)
+public class DataJpaTestWithAutoConfigureTestDatabaseReplaceAutoConfiguredIntegrationTests {
+
+ @Autowired
+ private TestEntityManager entities;
+
+ @Autowired
+ private ExampleRepository repository;
+
+ @Autowired
+ private DataSource dataSource;
+
+ @Test
+ public void testRepository() throws Exception {
+ this.entities.persist(new ExampleEntity("spring", "123"));
+ this.entities.persist(new ExampleEntity("boot", "124"));
+ this.entities.flush();
+ ExampleEntity found = this.repository.findByReference("124");
+ assertThat(found.getName()).isEqualTo("boot");
+ }
+
+ @Test
+ public void replacesAutoConfiguredDataSource() throws Exception {
+ String product = this.dataSource.getConnection().getMetaData()
+ .getDatabaseProductName();
+ assertThat(product).startsWith("HSQL");
+ }
+
+ @Configuration
+ @EnableAutoConfiguration // Will auto-configure H2
+ static class Config {
+
+ }
+
+}
diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestWithAutoConfigureTestDatabaseReplaceAutoConfiguredWithoutOverrideIntegrationTests.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestWithAutoConfigureTestDatabaseReplaceAutoConfiguredWithoutOverrideIntegrationTests.java
new file mode 100644
index 0000000000..029810eb4f
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestWithAutoConfigureTestDatabaseReplaceAutoConfiguredWithoutOverrideIntegrationTests.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * 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.springframework.boot.test.autoconfigure.orm.jpa;
+
+import javax.sql.DataSource;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.orm.jpa.AutoConfigureTestDatabase.Replace;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Integration tests for {@link DataJpaTest}.
+ *
+ * @author Phillip Webb
+ */
+@RunWith(SpringRunner.class)
+@DataJpaTest
+@AutoConfigureTestDatabase(replace = Replace.AUTO_CONFIGURED)
+public class DataJpaTestWithAutoConfigureTestDatabaseReplaceAutoConfiguredWithoutOverrideIntegrationTests {
+
+ @Autowired
+ private TestEntityManager entities;
+
+ @Autowired
+ private ExampleRepository repository;
+
+ @Autowired
+ private DataSource dataSource;
+
+ @Test
+ public void testRepository() throws Exception {
+ this.entities.persist(new ExampleEntity("spring", "123"));
+ this.entities.persist(new ExampleEntity("boot", "124"));
+ this.entities.flush();
+ ExampleEntity found = this.repository.findByReference("124");
+ assertThat(found.getName()).isEqualTo("boot");
+ }
+
+ @Test
+ public void usesDefaultEmbeddedDatabase() throws Exception {
+ String product = this.dataSource.getConnection().getMetaData()
+ .getDatabaseProductName();
+ // @AutoConfigureTestDatabase would use H2 but HSQL is manually defined
+ assertThat(product).startsWith("HSQL");
+ }
+
+}
diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestWithAutoConfigureTestDatabaseReplaceExplicitIntegrationTests.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestWithAutoConfigureTestDatabaseReplaceExplicitIntegrationTests.java
new file mode 100644
index 0000000000..7d033335af
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestWithAutoConfigureTestDatabaseReplaceExplicitIntegrationTests.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * 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.springframework.boot.test.autoconfigure.orm.jpa;
+
+import javax.sql.DataSource;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.jdbc.EmbeddedDatabaseConnection;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Integration tests for {@link DataJpaTest}.
+ *
+ * @author Phillip Webb
+ */
+@RunWith(SpringRunner.class)
+@DataJpaTest
+@AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.HSQL)
+public class DataJpaTestWithAutoConfigureTestDatabaseReplaceExplicitIntegrationTests {
+
+ @Autowired
+ private TestEntityManager entities;
+
+ @Autowired
+ private ExampleRepository repository;
+
+ @Autowired
+ private DataSource dataSource;
+
+ @Test
+ public void testRepository() throws Exception {
+ this.entities.persist(new ExampleEntity("spring", "123"));
+ this.entities.persist(new ExampleEntity("boot", "124"));
+ this.entities.flush();
+ ExampleEntity found = this.repository.findByReference("124");
+ assertThat(found.getName()).isEqualTo("boot");
+ }
+
+ @Test
+ public void replacesDefinedDatasourceWithExplicit() throws Exception {
+ // H2 is explicitly defined by HSQL is the override
+ String product = this.dataSource.getConnection().getMetaData()
+ .getDatabaseProductName();
+ assertThat(product).startsWith("HSQL");
+ }
+
+ @Configuration
+ @EnableAutoConfiguration
+ static class Config {
+
+ @Bean
+ public DataSource dataSource() {
+ EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
+ .setType(EmbeddedDatabaseType.H2);
+ return builder.build();
+ }
+
+ }
+
+}
diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestWithAutoConfigureTestDatabaseReplaceNoneIntegrationTests.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestWithAutoConfigureTestDatabaseReplaceNoneIntegrationTests.java
new file mode 100644
index 0000000000..bef5f4b949
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestWithAutoConfigureTestDatabaseReplaceNoneIntegrationTests.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * 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.springframework.boot.test.autoconfigure.orm.jpa;
+
+import javax.sql.DataSource;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.orm.jpa.AutoConfigureTestDatabase.Replace;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Integration tests for {@link DataJpaTest}.
+ *
+ * @author Phillip Webb
+ */
+@RunWith(SpringRunner.class)
+@DataJpaTest
+@AutoConfigureTestDatabase(replace = Replace.NONE)
+public class DataJpaTestWithAutoConfigureTestDatabaseReplaceNoneIntegrationTests {
+
+ @Autowired
+ private TestEntityManager entities;
+
+ @Autowired
+ private ExampleRepository repository;
+
+ @Autowired
+ private DataSource dataSource;
+
+ @Test
+ public void testRepository() throws Exception {
+ this.entities.persist(new ExampleEntity("spring", "123"));
+ this.entities.persist(new ExampleEntity("boot", "124"));
+ this.entities.flush();
+ ExampleEntity found = this.repository.findByReference("124");
+ assertThat(found.getName()).isEqualTo("boot");
+ }
+
+ @Test
+ public void usesDefaultEmbeddedDatabase() throws Exception {
+ // HSQL is explicitly defined and should not be replaced
+ String product = this.dataSource.getConnection().getMetaData()
+ .getDatabaseProductName();
+ assertThat(product).startsWith("HSQL");
+ }
+
+}
diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/ExampleComponent.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/ExampleComponent.java
new file mode 100644
index 0000000000..2c369fdc4f
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/ExampleComponent.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * 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.springframework.boot.test.autoconfigure.orm.jpa;
+
+import org.springframework.stereotype.Component;
+
+/**
+ * Example component used with {@link DataJpaTest} tests.
+ *
+ * @author Phillip Webb
+ */
+@Component
+public class ExampleComponent {
+
+}
diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/ExampleDataJpaApplication.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/ExampleDataJpaApplication.java
new file mode 100644
index 0000000000..5331a2fba5
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/ExampleDataJpaApplication.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * 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.springframework.boot.test.autoconfigure.orm.jpa;
+
+import javax.sql.DataSource;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
+
+/**
+ * Example {@link SpringBootApplication} used with {@link DataJpaTest} tests.
+ *
+ * @author Phillip Webb
+ */
+@SpringBootApplication
+public class ExampleDataJpaApplication {
+
+ @Bean
+ public DataSource dataSource() {
+ EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
+ .setType(EmbeddedDatabaseType.HSQL);
+ return builder.build();
+ }
+
+}
diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/ExampleEntity.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/ExampleEntity.java
new file mode 100644
index 0000000000..2e0fa97fd1
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/ExampleEntity.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * 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.springframework.boot.test.autoconfigure.orm.jpa;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+/**
+ * Example entity used with {@link DataJpaTest} tests.
+ *
+ * @author Phillip Webb
+ */
+@Entity
+public class ExampleEntity {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ private String name;
+
+ private String reference;
+
+ protected ExampleEntity() {
+ }
+
+ public ExampleEntity(String name, String reference) {
+ super();
+ this.name = name;
+ this.reference = reference;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public String getReference() {
+ return this.reference;
+ }
+
+}
diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/ExampleRepository.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/ExampleRepository.java
new file mode 100644
index 0000000000..a783333cee
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/ExampleRepository.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * 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.springframework.boot.test.autoconfigure.orm.jpa;
+
+import org.springframework.data.repository.Repository;
+
+/**
+ * Example repository used with {@link DataJpaTest} tests.
+ *
+ * @author Phillip Webb
+ */
+public interface ExampleRepository extends Repository {
+
+ ExampleEntity findByReference(String reference);
+
+}
diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestEntityManagerTests.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestEntityManagerTests.java
new file mode 100644
index 0000000000..965dc2489a
--- /dev/null
+++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestEntityManagerTests.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * 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.springframework.boot.test.autoconfigure.orm.jpa;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceUnitUtil;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import org.springframework.orm.jpa.EntityManagerHolder;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Tests for {@link TestEntityManager}.
+ *
+ * @author Phillip Webb
+ */
+public class TestEntityManagerTests {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Mock
+ private EntityManagerFactory entityManagerFactory;
+
+ @Mock
+ private EntityManager entityManager;
+
+ @Mock
+ private PersistenceUnitUtil persistenceUnitUtil;
+
+ private TestEntityManager testEntityManager;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ this.testEntityManager = new TestEntityManager(this.entityManagerFactory);
+ given(this.entityManagerFactory.getPersistenceUnitUtil())
+ .willReturn(this.persistenceUnitUtil);
+ }
+
+ @Test
+ public void createWhenEntityManagerIsNullShouldThrowException() throws Exception {
+ this.thrown.expect(IllegalArgumentException.class);
+ this.thrown.expectMessage("EntityManagerFactory must not be null");
+ new TestEntityManager(null);
+ }
+
+ @Test
+ public void persistAndGetIdShouldPersistAndGetId() throws Exception {
+ bindEntityManager();
+ TestEntity entity = new TestEntity();
+ given(this.persistenceUnitUtil.getIdentifier(entity)).willReturn(null, 123);
+ Object result = this.testEntityManager.persistAndGetId(entity);
+ verify(this.entityManager).persist(entity);
+ assertThat(result).isEqualTo(123);
+ }
+
+ @Test
+ public void persistAndGetIdForTypeShouldPersistAndGetId() throws Exception {
+ bindEntityManager();
+ TestEntity entity = new TestEntity();
+ given(this.persistenceUnitUtil.getIdentifier(entity)).willReturn(null, 123);
+ Integer result = this.testEntityManager.persistAndGetId(entity, Integer.class);
+ verify(this.entityManager).persist(entity);
+ assertThat(result).isEqualTo(123);
+ }
+
+ @Test
+ public void persistShouldPersist() throws Exception {
+ bindEntityManager();
+ TestEntity entity = new TestEntity();
+ TestEntity result = this.testEntityManager.persist(entity);
+ verify(this.entityManager).persist(entity);
+ assertThat(result).isSameAs(entity);
+ }
+
+ @Test
+ public void persistWhenAlreadyHasIdShouldThrowException() throws Exception {
+ bindEntityManager();
+ TestEntity entity = new TestEntity();
+ given(this.persistenceUnitUtil.getIdentifier(entity)).willReturn(123);
+ this.thrown.expect(IllegalStateException.class);
+ this.thrown.expectMessage(
+ "Entity " + TestEntity.class.getName() + " already has an ID");
+ this.testEntityManager.persistAndGetId(entity, Integer.class);
+ }
+
+ @Test
+ public void persistAndFlushShouldPersistAndFlush() throws Exception {
+ bindEntityManager();
+ TestEntity entity = new TestEntity();
+ TestEntity result = this.testEntityManager.persistAndFlush(entity);
+ verify(this.entityManager).persist(entity);
+ verify(this.entityManager).flush();
+ assertThat(result).isSameAs(entity);
+ }
+
+ @Test
+ public void persistFlushFindShouldPersistAndFlushAndFind() throws Exception {
+ bindEntityManager();
+ TestEntity entity = new TestEntity();
+ TestEntity found = new TestEntity();
+ given(this.persistenceUnitUtil.getIdentifier(entity)).willReturn(null, 123);
+ given(this.entityManager.find(TestEntity.class, 123)).willReturn(found);
+ TestEntity result = this.testEntityManager.persistFlushFind(entity);
+ verify(this.entityManager).persist(entity);
+ verify(this.entityManager).flush();
+ assertThat(result).isSameAs(found);
+ }
+
+ @Test
+ public void mergeShouldMerge() throws Exception {
+ bindEntityManager();
+ TestEntity entity = new TestEntity();
+ given(this.entityManager.merge(entity)).willReturn(entity);
+ TestEntity result = this.testEntityManager.merge(entity);
+ verify(this.entityManager).merge(entity);
+ assertThat(result).isSameAs(entity);
+ }
+
+ @Test
+ public void removeShouldRemove() throws Exception {
+ bindEntityManager();
+ TestEntity entity = new TestEntity();
+ this.testEntityManager.remove(entity);
+ verify(this.entityManager).remove(entity);
+ }
+
+ @Test
+ public void findShouldFind() throws Exception {
+ bindEntityManager();
+ TestEntity entity = new TestEntity();
+ given(this.entityManager.find(TestEntity.class, 123)).willReturn(entity);
+ TestEntity result = this.testEntityManager.find(TestEntity.class, 123);
+ assertThat(result).isSameAs(entity);
+ }
+
+ @Test
+ public void flushShouldFlush() throws Exception {
+ bindEntityManager();
+ this.testEntityManager.flush();
+ verify(this.entityManager).flush();
+ }
+
+ @Test
+ public void refreshShouldRefresh() throws Exception {
+ bindEntityManager();
+ TestEntity entity = new TestEntity();
+ this.testEntityManager.refresh(entity);
+ verify(this.entityManager).refresh(entity);
+ }
+
+ @Test
+ public void clearShouldClear() throws Exception {
+ bindEntityManager();
+ this.testEntityManager.clear();
+ verify(this.entityManager).clear();
+ }
+
+ @Test
+ public void detachShouldDetach() throws Exception {
+ bindEntityManager();
+ TestEntity entity = new TestEntity();
+ this.testEntityManager.detach(entity);
+ verify(this.entityManager).detach(entity);
+ }
+
+ @Test
+ public void getIdForTypeShouldGetId() throws Exception {
+ TestEntity entity = new TestEntity();
+ given(this.persistenceUnitUtil.getIdentifier(entity)).willReturn(123);
+ Integer result = this.testEntityManager.getId(entity, Integer.class);
+ assertThat(result).isEqualTo(123);
+ }
+
+ @Test
+ public void getIdForTypeWhenTypeIsWrongShouldThrowException() throws Exception {
+ TestEntity entity = new TestEntity();
+ given(this.persistenceUnitUtil.getIdentifier(entity)).willReturn(123);
+ this.thrown.expectMessage("ID missmatch Object of class [java.lang.Integer] "
+ + "must be an instance of class java.lang.Long");
+ this.testEntityManager.getId(entity, Long.class);
+ }
+
+ @Test
+ public void getIdShouldGetId() throws Exception {
+ TestEntity entity = new TestEntity();
+ given(this.persistenceUnitUtil.getIdentifier(entity)).willReturn(123);
+ Object result = this.testEntityManager.getId(entity);
+ assertThat(result).isEqualTo(123);
+ }
+
+ @Test
+ public void getEntityManagerShouldGetEntityManager() throws Exception {
+ bindEntityManager();
+ assertThat(this.testEntityManager.getEntityManager())
+ .isEqualTo(this.entityManager);
+ }
+
+ @Test
+ public void getEntityManagerWhenNotSetShouldThrowException() throws Exception {
+ this.thrown.expect(IllegalStateException.class);
+ this.thrown.expectMessage("No transactional EnitiyManager found");
+ this.testEntityManager.getEntityManager();
+ }
+
+ private void bindEntityManager() {
+ EntityManagerHolder holder = new EntityManagerHolder(this.entityManager);
+ TransactionSynchronizationManager.bindResource(this.entityManagerFactory, holder);
+ }
+
+ static class TestEntity {
+
+ }
+
+}