Help us understand the problem. What is going on with this article?

[Java][Spring] Spring Boot 1.4 -> 1.2 ダウングレードメモ

More than 3 years have passed since last update.

こんなことをするひとはいないと思いますが、せっかく苦しんだのでメモしておきます。

この文章の表記について

:grin: 1.4: 1.4の場合のやりかたです。
:smirk: 1.2: 1.2の場合のやりかたです。

実装関係

@EntityScan

:grin: 1.4: org.springframework.boot.autoconfigure.domain.EntityScan
:smirk: 1.2: org.springframework.boot.orm.jpa.EntityScan

DI

:grin: 1.4: 自明であれば@Autowiredを付けなくてもDIしてくます。
:smirk: 1.2: @Autowired付けましょう。

テスト関係

テストランナー

:grin: 1.4: @RunWith(SpringRunner.class)
:smirk: 1.2: @RunWith(SpringJUnit4ClassRunner.class)

Springを使ったテスト

:grin: 1.4: @SpringBootTestを付ける
:smirk: 1.2: @SpringApplicationConfiguration(classes = アプリケーションクラス)を付ける

http://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/SpringApplicationConfiguration.html

データベース統合テスト

:grin: 1.4: @DataJpaTestをテストクラスに付ける。
:smirk: 1.2: ちと大変。

@DataJpaTestはこんなことをしてくれているそうです。

  1. インメモリデータベースを設定
  2. Hibernate/Spring Data/Datasourceを設定
  3. @EntityScanを実行
  4. SQLログを有効化

全部がんばらないといけないかと思いましたが、これだけのことをやれば大丈夫そうです。

  1. @EntityScan@EnableJpaRepositoriesを付けたアプリケーションコンテキストクラスを作成。
  2. TestEntityManagerクラスを作成(1.4からぱくる)
  3. TestEntityManagerを返すBeanを作成(1.4からぱくる)
  4. テストクラスに@Transactional@SpringApplicationConfigurationを付ける。

順番にやっていきます。

@EntityScan@EnableJpaRepositoriesを付けたアプリケーションコンテキストクラスを作成

TestApplication.java
@SpringBootApplication
@EnableJpaRepositories(レポジトリクラスの場所)
@EntityScan(エンティティクラスの場所)
@EnableJpaAuditing // これは今回関係ない
public class TestApplication {

}

TestEntityManagerクラスを作成(1.4からぱくる)

元ソースはここにあります。
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/

TestEntityManager.java
public class TestEntityManager {

    private final EntityManagerFactory entityManagerFactory;

    public TestEntityManager(EntityManagerFactory entityManagerFactory) {
        Assert.notNull(entityManagerFactory, "EntityManagerFactory must not be null");
        this.entityManagerFactory = entityManagerFactory;
    }

    public <E> E persist(E entity) {
        getEntityManager().persist(entity);
        return entity;
    }

    public void flush() {
        getEntityManager().flush();
    }

    public <E> E persistAndFlush(E entity) {
        persist(entity);
        flush();
        return entity;
    }

    public void detach(Object entity) {
        getEntityManager().detach(entity);
    }

    public <E> E find(Class<E> entityClass, Object primaryKey) {
        return getEntityManager().find(entityClass, primaryKey);
    }

    public final EntityManager getEntityManager() {
        EntityManager manager = EntityManagerFactoryUtils
                .getTransactionalEntityManager(this.entityManagerFactory);
        Assert.state(manager != null, "No transactional EntityManager found");
        return manager;
    }
}

TestEntityManagerを返すBeanを作成(1.4からぱくる)

TestEntityManagerConfigure.java
@Configuration
@AutoConfigureAfter(HibernateJpaAutoConfiguration.class)
public class TestEntityManagerConfigure {

    @Bean
    @ConditionalOnMissingBean
    public TestEntityManager testEntityManager(
            EntityManagerFactory entityManagerFactory) {
        return new TestEntityManager(entityManagerFactory);
    }

}

テストクラスに@Transactional@SpringApplicationConfigurationを付ける

MySomeRepositoryTest.java
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestApplication.class)
@Transactional
public class MySomeRepositoryTest {

    @Autowired
    private MySomeRepository instance;

    @Autowired
    private TestEntityManager em;

    @Test
    public void testSomeMethod {
     // ...
    }

}


モック化したインスタンスをインジェクトする

:grin: 1.4: モック化したいインスタンス変数に@MockBeanを付ける
:smirk: 1.2: モック化したインスタンスを返す@Beanを定義して@Primaryを付ける

1.4の場合

MySomeTest.java
    @MockBean
    private MyTargetClass mock;

1.2の場合

特定の@Configurationクラスだけ有効になるように、@Profileを付けています。

MySomeTest.java
@ActiveProfiles("MySomeTest")
public class MySomeTest {
    @Autowired
    private MyTargetClass mock;
}
MySomeTestConfig.java
@Configuration
@Profile("MySomeTest")
public class MySomeTestConfig {
    @Bean
    @Primary
    public MyTargetClass myTargetClass() {
        return Mockito.mock(MyTargetClass.class);
    }
}

旅は続く。。。

また何か発見があったら追記していきます。

sengoku
テスト原理主義者。 記事は日々の記録です。2020年は、Java。2019年は、Angular/TypeScript/ASP.NET Core/C#が多めです。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした