Подтвердить что ты не робот

Как настроить JPA для тестирования в Maven

Есть ли способ настроить второй файл persistence.xml в проекте Maven, чтобы он использовался для тестирования вместо обычного, который используется для развертывания?

Я попытался поместить persistence.xml в src/test/resources/META-INF, который копируется в целевые/тестовые классы /META -INF, но, похоже, target/classes/META-INF (копия из src/main/resources), несмотря на то, что mvn -X test перечисляет записи пути к классу в правильном порядке:

[DEBUG] Test Classpath :
[DEBUG]   /home/uqpbecke/dev/NetBeansProjects/UserManager/target/test-classes
[DEBUG]   /home/uqpbecke/dev/NetBeansProjects/UserManager/target/classes
[DEBUG]   /home/uqpbecke/.m2/repository/junit/junit/4.5/junit-4.5.jar
...

Я хотел бы иметь возможность запускать тесты с простой конфигурацией hsqldb без необходимости изменять версию развертывания конфигурации JPA, в идеале, прямо после проверки проекта без какой-либо локальной настройки.

4b9b3361

Ответ 1

Следующее будет работать для Maven 2.1+ (до этого не было фазы между тестом и пакетом, к которым вы могли бы привязать выполнение).

Вы можете использовать maven-antrun-plugin для замены persistence.xml тестовой версией на время тестов, а затем восстановить правильную версию до того, как пакет будет упакован.

В этом примере предполагается, что производственная версия - src/main/resources/META-INF/persistence.xml, а тестовая версия - src/test/resources/META-INF/persistence.xml, поэтому они будут скопированы в целевую/классы/META-INF и целевые/тестовые классы /META -INF соответственно.

Было бы более элегантно инкапсулировать это в mojo, но поскольку вы только копируете файл, это кажется излишним.

<plugin>
  <artifactId>maven-antrun-plugin</artifactId>
  <version>1.3</version>
  <executions>
    <execution>
      <id>copy-test-persistence</id>
      <phase>process-test-resources</phase>
      <configuration>
        <tasks>
          <!--backup the "proper" persistence.xml-->
          <copy file="${project.build.outputDirectory}/META-INF/persistence.xml" tofile="${project.build.outputDirectory}/META-INF/persistence.xml.proper"/>
          <!--replace the "proper" persistence.xml with the "test" version-->
          <copy file="${project.build.testOutputDirectory}/META-INF/persistence.xml" tofile="${project.build.outputDirectory}/META-INF/persistence.xml"/>
        </tasks>
      </configuration>
      <goals>
        <goal>run</goal>
      </goals>
    </execution>
    <execution>
      <id>restore-persistence</id>
      <phase>prepare-package</phase>
      <configuration>
        <tasks>
          <!--restore the "proper" persistence.xml-->
          <copy file="${project.build.outputDirectory}/META-INF/persistence.xml.proper" tofile="${project.build.outputDirectory}/META-INF/persistence.xml"/>
        </tasks>
      </configuration>
      <goals>
        <goal>run</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Ответ 2

В проекте EE6/CDI/JPA тест src/test/resources/META-INF/persistence.xml подбирается просто отлично, без какой-либо дополнительной настройки.

При использовании JPA в Spring в контексте приложения, используемом для тестирования, выполняется следующее:

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <!--
        JPA requires META-INF/persistence.xml, but somehow prefers the one
        in classes/META-INF over the one in test-classes/META-INF. Spring
        to the rescue, as it allows for setting things differently, like by
        referring to "classpath:persistence-TEST.xml". Or, simply referring
        to "META-INF/persistence.xml" makes JPA use the test version too: 
    -->
    <property name="persistenceXmlLocation" value="META-INF/persistence.xml" />

    <!-- As defined in /src/test/resources/META-INF/persistence.xml -->
    <property name="persistenceUnitName" value="myTestPersistenceUnit" />
    <property name="jpaVendorAdapter">
        <bean
            class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        </bean>
    </property>
</bean>

Здесь /src/test/resources/META-INF/persistence.xml (скопировано в target/test-classes) было бы предпочтительнее /src/main/resources/META-INF/persistence.xml (скопировано в target/classes).

К сожалению, расположение файла persistence.xml также определяет так называемый " корневой узел персистентности", который затем определяет, какие классы сканируются для аннотаций @Entity. Таким образом, использование /src/test/resources/META-INF/persistence.xml будет сканировать классы в target/test-classes, а не классы в target/classes (где будут тестироваться классы, которые должны быть протестированы).

Следовательно, для тестирования нужно явно добавить записи <class> в persistence.xml, чтобы избежать java.lang.IllegalArgumentException: Not an entity: class .... Потребность в элементах <class> можно избежать, используя другое имя файла, например persistence-TEST.xml, и поместите этот файл в ту же папку, что и обычный файл persistence.xml. Контекст Spring из тестовой папки может просто ссылаться на <property name="persistenceXmlLocation" value="META-INF/persistence-TEST.xml" />, а Spring найдет его для вас в src/main.

В качестве альтернативы можно было бы поддерживать persistence.xml то же самое для фактического приложения и тестов и определять только один из src/main. Большинство конфигураций, таких как драйверы, диалект и дополнительные учетные данные, могут быть выполнены в контексте Spring. Также параметры, такие как hibernate.hbm2ddl.auto, могут быть переданы в контексте:

<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <!-- For example: com.mysql.jdbc.Driver or org.h2.Driver -->
    <property name="driverClassName" value="#{myConfig['db.driver']}" />
    <!-- For example: jdbc:mysql://localhost:3306/myDbName or 
        jdbc:h2:mem:test;DB_CLOSE_DELAY=-1 -->
    <property name="url" value="#{myConfig['db.url']}" />
    <!-- Ignored for H2 -->
    <property name="username" value="#{myConfig['db.username']}" />
    <property name="password" value="#{myConfig['db.password']}" />
</bean>

<bean id="jpaAdaptor"
    class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <!-- For example: org.hibernate.dialect.MySQL5Dialect or 
        org.hibernate.dialect.H2Dialect -->
    <property name="databasePlatform" value="#{myConfig['db.dialect']}" />
</bean>

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter" ref="jpaAdapter" />
    <property name="jpaProperties">
        <props>
            <!-- For example: validate, update, create or create-drop -->
            <prop key="hibernate.hbm2ddl.auto">#{myConfig['db.ddl']}</prop>
            <prop key="hibernate.show_sql">#{myConfig['db.showSql']}</prop>
            <prop key="hibernate.format_sql">true</prop>
        </props>
    </property>
</bean>

Ответ 3

Кажется, что несколько файлов persistence.xml - общая проблема с JPA, решаемая только трюками с загрузкой классов.

Обходной путь, который работает для меня, заключается в определении нескольких единиц сохранения в одном файле persistence.xml, а затем убедитесь, что ваш код развертывания и тестирования использует другую привязку (в Spring вы можете установить свойство persistenceUnitName на менеджер объектов factory). Он загрязняет ваш файл развертывания тестовой конфигурацией, но если вы не возражаете, что он работает нормально.

Ответ 4

Я пробовал подход ClassLoaderProxy, но имел проблему, что аннотированные классы JPA не обрабатываются как постоянные классы по спячке.

Так решил попробовать, не используя persistence.xml. Преимущество в том, что сборка maven и тест Eclipse JUnit будут работать без изменений.

У меня есть постоянный класс поддержки для тестирования JUnit.

public class PersistenceTestSupport {

    protected EntityManager em;
    protected EntityTransaction et;

    /**
     * Setup the the {@code EntityManager} and {@code EntityTransaction} for
     * local junit testing.
     */
    public void setup() {

        Properties props = new Properties();
        props.put("hibernate.hbm2ddl.auto", "create-drop");
        props.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
        props.put("hibernate.connection.url", "jdbc:mysql://localhost/db_name");
        props.put("hibernate.connection.driver_class", "com.mysql.jdbc.Driver");
        props.put("hibernate.connection.username", "user");
        props.put("hibernate.connection.password", "****");

        Ejb3Configuration cfg = new Ejb3Configuration();
        em = cfg.addProperties(props)
            .addAnnotatedClass(Class1.class)
            .addAnnotatedClass(Class2.class)
            ...
                    .addAnnotatedClass(Classn.class)
            .buildEntityManagerFactory()
            .createEntityManager();

        et = em.getTransaction();
    }
}

Мои тестовые классы просто расширяют PersistenceTestSupport и вызывают setup() в TestCase.setup().

Единственным недостатком является сохранение постоянных классов до даты, но для тестирования JUnit это приемлемо для меня.

Ответ 5

Добавьте persistance.xml для тестов: /src/test/resources/META-INF/persistence.xml Как сказал @Arjan, это изменит корневой модуль на стороне устойчивости, а классы объектов будут проверяться в целевых/тестовых классах. Чтобы обработать это, добавьте элемент jar-file в этот persistance.xml:

/src/test/resources/META-INF/persistence.xml

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">
    <persistence-unit name="com.some.project">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <jar-file>${project.basedir}/target/classes</jar-file>
        <properties>
            <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/test_database" />
            <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
            <property name="javax.persistence.jdbc.user" value="user" />
            <property name="javax.persistence.jdbc.password" value="..." />
        </properties>
    </persistence-unit>
</persistence>

Затем добавьте фильтрацию тестовых ресурсов в ваш pom.xml:

<project>
    ...
    <build>
        ...
        <testResources>
            <testResource>
                <directory>src/test/resources</directory>
                <filtering>true</filtering>
            </testResource>
        </testResources>
        ...
    </build>
...
</project>

Это будет работать, потому что jar-file может быть нацелен на каталоги, а не только на файлы jar.

Ответ 6

Я предпочитаю решение использовать различные persistence.xml для тестирования и производства как Rich Seller post (спасибо!!).

Но нужно изменить:

<copy file="${project.build.outputDirectory}/META-INF/persistence.xml.proper" tofile="${project.build.outputDirectory}/META-INF/persistence.xml"/>

для

<move file="${project.build.outputDirectory}/META-INF/persistence.xml.proper" tofile="${project.build.outputDirectory}/META-INF/persistence.xml" overwrite="true"/>

Чтобы persistence.xml.proper не был встроен в .jar файл

Ответ 7

Этот ответ может показаться глупым, но я искал способ, который позволяет запускать те тесты из eclipse на Run AsJUnit Test. Вот как я это сделал:

@BeforeClass
public static void setUp() throws IOException {
    Files.copy(new File("target/test-classes/META-INF/persistence.xml"), new File("target/classes/META-INF/persistence.xml"));
    // ...
}

Я просто копирую test/persistence.xml в classes/persistence.xml. Это работает.

Ответ 8

Сохраните две копии файла persistence.xml. Один для тестирования и другой для нормальной сборки.

Жизненный цикл по умолчанию копирует build persistence.xml в src/test/resources/META-INF

Создайте отдельный профиль, который при запуске скопирует проверку persistence.xml на src/test/resources/META-INF

Ответ 9

Persistence.xml используется как отправная точка для поиска классов сущностей, если вы не указали все классы явно и не добавили. Поэтому, если вы хотите переопределить этот файл другим, скажем, из src/test/resources, вам нужно указать каждый отдельный класс сущности в этом втором persistence.xml, иначе класс сущности не будет найден.

Другим решением было бы перезаписать файл, используя плагин maven-resources-plugin (цель "копии-ресурсы" ). Но тогда вы должны перезаписать его дважды, один раз для тестирования (например, фазовые процессы-тесты-классы) и один раз для реальной упаковки (фаза "подготовить-пакет" ).

Ответ 10

Я пытаюсь сделать то же самое. У меня есть решение, которое работает для меня - ваше может варьироваться (и вам может не понравиться решение... это немного низкоуровневое).

Я наткнулся на статью в сети, где они использовали пользовательский загрузчик классов, чтобы сделать что-то подобное, что послужило источником вдохновения. Если кто-то может увидеть, как улучшить, тогда предложения будут приветствоваться кстати. Для развертывания я полагаюсь на инъекцию контейнера EntityManager, но для тестирования я сам его создаю с помощью этого кода:

final Thread currentThread = Thread.currentThread();
final ClassLoader saveClassLoader = currentThread.getContextClassLoader();
currentThread.setContextClassLoader(new ClassLoaderProxy(saveClassLoader));

EntityManagerFactory emFactory = Persistence.createEntityManagerFactory("test");
em = emFactory.createEntityManager();

Тогда ClassLoaderProxy примерно так же минимален, как вы можете получить, и просто перенаправляет запросы на META-INF/persistence.xml в META-INF/test-persist.xml:

public class ClassLoaderProxy extends ClassLoader {

    public ClassLoaderProxy(final ClassLoader parent) {
        super();
    }

    @Override
    public Enumeration<URL> getResources(final String name) throws IOException {
        if (!"META-INF/persistence.xml".equals(name)) {
            return super.getResources(name);
        } else {
            System.out.println("Redirecting persistence.xml to test-persist.xml");
            return super.getResources("META-INF/test-persist.xml");
        }
    }
}

Просто, чтобы объяснить это немного больше:

  • Есть два файла persistence.xml(один из них - persistence.xml, который используется вне тестирования и один из них - test-persist.xml, который используется для тестов).
  • Пользовательский загрузчик классов активен только для модульных тестов (для развертывания все нормально)
  • Пользовательский загрузчик классов перенаправляет запросы на "META-INF/persistence.xml" в тестовую версию ( "META-INF/test-persist.xml" ).

Я изначально сталкивался с некоторыми проблемами, потому что Hibernate вернется назад (каким-то образом) к загрузчику классов, который использовался для загрузки Hibernate (по крайней мере, я думаю, это то, что происходит). Я обнаружил, что включение кода переключения ClassLoader (первого блока) в качестве статического блока в тестовом примере будет загружаться до спящего режима, но в зависимости от структуры unit test вам также может понадобиться поместить тот же код в другой места (yuck).

Ответ 11

Другим подходом является использование отдельного persistence.xml для тестирования (test/../META-INF/persistence.xml, но переопределить сканер следующим образом: -

тестирование persistence.xml должно содержать

<property name="hibernate.ejb.resource_scanner" value = "...TestScanner" />

Код для нового класса TestScanner выглядит следующим образом.

import java.lang.annotation.Annotation;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Set;
import org.hibernate.ejb.packaging.NamedInputStream;
import org.hibernate.ejb.packaging.NativeScanner;


public class TestScanner extends NativeScanner
{

@Override
public Set <Class <?> > 
getClassesInJar (URL jar, Set <Class <? extends Annotation> > annotations)
{  return super.getClassesInJar (getUpdatedURL (jar), annotations); }

@Override
public Set <NamedInputStream> 
getFilesInJar (URL jar, Set <String> patterns)
{  return super.getFilesInJar (getUpdatedURL (jar), patterns); }

@Override
public Set <Package> 
getPackagesInJar (URL jar, Set <Class <? extends Annotation> > annotations)
{  return super.getPackagesInJar (getUpdatedURL (jar), annotations); }

private URL getUpdatedURL (URL url)
{
  String oldURL = url.toExternalForm ();
  String newURL = oldURL.replaceAll ("test-classes", "classes");
  URL result;
  try {
    result = newURL.equals (oldURL) ? url : new URL (newURL);
  } catch (MalformedURLException e)
  {  // Whatever  }
  return result;
}

}

Ответ 12

поместите тесты в собственный проект maven с его persistence.xml

Ответ 14

Я бы предложил использовать разные профили maven, где вы могли бы фильтровать файлы database.proprerties и иметь один файл database.properties для каждого профиля.

Таким образом, вам не нужно сохранять дубликаты других файлов конфигурации, кроме как .properties.

<properties>
    <!-- Used to locate the profile specific configuration file. -->
    <build.profile.id>default</build.profile.id>
    <!-- Only unit tests are run by default. -->
    <skip.integration.tests>true</skip.integration.tests>
    <skip.unit.tests>false</skip.unit.tests>
    <integration.test.files>**/*IT.java</integration.test.files>
</properties>
<profiles>
    <profile>
        <id>default</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <!--
                Specifies the build profile id, which is used to find out the correct properties file.
                This is not actually necessary for this example, but it can be used for other purposes.
            -->
            <build.profile.id>default</build.profile.id>
            <skip.integration.tests>true</skip.integration.tests>
            <skip.unit.tests>false</skip.unit.tests>
        </properties>
        <build>
            <filters>
                <!--
                    Specifies path to the properties file, which contains profile specific
                    configuration. In this case, the configuration file should be the default spring/database.properties file
                -->
                <filter>src/main/resources/META-INF/spring/database.properties</filter>
            </filters>
            <resources>
                <!--
                    Placeholders found from files located in the configured resource directories are replaced
                    with values found from the profile specific configuration files.
                -->
                <resource>
                    <filtering>true</filtering>
                    <directory>src/main/resources</directory>
                    <!--
                        You can also include only specific files found from the configured directory or
                        exclude files. This can be done by uncommenting following sections and adding
                        the configuration under includes and excludes tags.
                    -->
                    <!--
                    <includes>
                        <include></include>
                    </includes>
                    <excludes>
                        <exclude></exclude>
                    </excludes>
                    -->
                </resource>
            </resources>
        </build>
    </profile>
    <profile>
        <id>integration</id>
        <properties>
            <!--
                Specifies the build profile id, which is used to find out the correct properties file.
                This is not actually necessary for this example, but it can be used for other purposes.
            -->
            <build.profile.id>integration</build.profile.id>
            <skip.integration.tests>false</skip.integration.tests>
            <skip.unit.tests>true</skip.unit.tests>
        </properties>
        <build>
            <filters>
                <!--
                    Specifies path to the properties file, which contains profile specific
                    configuration. In this case, the configuration file is searched
                    from spring/profiles/it/ directory.
                -->
                <filter>src/main/resources/META-INF/spring/profiles/${build.profile.id}/database.properties</filter>
            </filters>
            <resources>
                <!--
                    Placeholders found from files located in the configured resource directories are replaced
                    with values found from the profile specific configuration files.
                -->
                <resource>
                    <filtering>true</filtering>
                    <directory>src/main/resources</directory>
                    <!--
                        You can also include only specific files found from the configured directory or
                        exclude files. This can be done by uncommenting following sections and adding
                        the configuration under includes and excludes tags.
                    -->
                    <!--
                    <includes>
                        <include></include>
                    </includes>
                    <excludes>
                        <exclude></exclude>
                    </excludes>
                    -->
                </resource>
            </resources>
        </build>
    </profile>
</profiles>

С помощью surefire для модульных тестов и failfe для тестов интеграции вы закончили.

    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.12</version>
    <configuration>
        <junitArtifactName>org.junit:com.springsource.org.junit</junitArtifactName>
        <!--see: https://issuetracker.springsource.com/browse/EBR-220-->
        <printSummary>false</printSummary>
        <redirectTestOutputToFile>true</redirectTestOutputToFile>
        <!-- Skips unit tests if the value of skip.unit.tests property is true -->
        <skipTests>${skip.unit.tests}</skipTests>
        <!-- Excludes integration tests when unit tests are run. -->
        <excludes>
            <exclude>${integration.test.files}</exclude>
        </excludes>
    </configuration>
</plugin>


<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>2.12</version>
    <configuration>
        <!-- Skips integration tests if the value of skip.integration.tests property is true -->
        <skipTests>${skip.integration.tests}</skipTests>
        <includes>
            <include>${integration.test.files}</include>
        </includes>
        <forkMode>once</forkMode>
        <!--
                            <reuseForks>false</reuseForks>
                            <forkCount>1</forkCount>
        -->
    </configuration>
    <executions>
        <execution>
            <id>integration-test</id>
            <goals>
                <goal>integration-test</goal>
            </goals>
        </execution>
        <execution>
            <id>verify</id>
            <goals>
                <goal>verify</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Теперь вам нужно всего лишь mvn test для ваших модульных тестов и mvn verify -Pintegration для ваших тестов интеграции. Очевидно, что вы должны создавать файлы database.properties в указанных (в профилях) путях (или в другом месте и изменять пути)

Базовая ссылка: http://www.petrikainulainen.net/programming/tips-and-tricks/creating-profile-specific-configuration-files-with-maven/

Ответ 15

Это расширение ответа Rich Seller с правильной обработкой Hibernate, нахождение нескольких файлов persistence.xml в пути к классам и предварительное тестирование состояния.

Настройка:

Создайте один файл сохранения для развертывания/упаковки и один для тестирования:

  • SRC/основные/ресурсы/persistence.xml

  • ЦСИ/ тест/ресурсы/persistence- Тестирование.xml

в вашем pom.xml добавьте это в раздел плагинов:

        <plugin>
            <artifactId>maven-antrun-plugin</artifactId>
            <version>1.3</version>
            <executions>
                <execution>
                    <id>copy-test-persistence</id>
                    <phase>process-test-resources</phase>
                    <configuration>
                        <tasks>
                            <echo>renaming deployment persistence.xml</echo>
                            <move file="${project.build.outputDirectory}/META-INF/persistence.xml" tofile="${project.build.outputDirectory}/META-INF/persistence.xml.proper"/>
                            <echo>replacing deployment persistence.xml with test version</echo>
                            <copy file="${project.build.testOutputDirectory}/META-INF/persistence-testing.xml" tofile="${project.build.outputDirectory}/META-INF/persistence.xml" overwrite="true"/>
                        </tasks>
                    </configuration>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
                <execution>
                    <id>restore-persistence</id>
                    <phase>prepare-package</phase>
                    <configuration>
                        <tasks>
                            <echo>restoring the deployment persistence.xml</echo>
                            <move file="${project.build.outputDirectory}/META-INF/persistence.xml.proper" tofile="${project.build.outputDirectory}/META-INF/persistence.xml" overwrite="true"/>
                        </tasks>
                    </configuration>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

Преимущества по сравнению с другими решениями

  • Не требуется дополнительный код Java
  • Только один persistence.xml в пути к классам
  • Как строительство, так и тестирование работают как ожидалось
  • Описание вывода на консоли (эхо)
  • Для упаковки состояние восстанавливается на 100%. Нет оставшихся файлов

Ответ 16

Другим вариантом для этого варианта использования было бы добавление нескольких единиц продолжительности, один из которых позволяет производить производство, а другой - для тестирования и соответственно вводить EntityManagerFactory.

Поместите обе единицы персистентности в файл persistence.xml фактического проекта и попросите тестовые примеры ввести правильный EntityManager. Пример ниже иллюстрирует, как это сделать с помощью guice. Пожалуйста, обратите внимание, что я остался в некотором издевательстве над оригинальностью, особый код для mockito был отмечен соответствующим образом и не требуется для инъекций.

public class HibernateTestDatabaseProvider extends AbstractModule {
    private static final ThreadLocal<EntityManager> ENTITYMANAGER_CACHE = new ThreadLocal<>();

    @Override
    public void configure() {
    }

    @Provides
    @Singleton
    public EntityManagerFactory provideEntityManagerFactory() {
        return Persistence.createEntityManagerFactory("my.test.persistence.unit");
    }

    @Provides
    public CriteriaBuilder provideCriteriaBuilder(EntityManagerFactory entityManagerFactory) {
        return entityManagerFactory.getCriteriaBuilder();
    }

    @Provides
    public EntityManager provideEntityManager(EntityManagerFactory entityManagerFactory) {
        EntityManager entityManager = ENTITYMANAGER_CACHE.get();
        if (entityManager == null) {
            // prevent commits on the database, requires mockito. Not relevant for this answer
            entityManager = spy(entityManagerFactory.createEntityManager());


            EntityTransaction et = spy(entityManager.getTransaction());
            when(entityManager.getTransaction()).thenReturn(et);
            doNothing().when(et).commit();

            ENTITYMANAGER_CACHE.set(entityManager);
        }
        return entityManager;
    }
}