web-dev-qa-db-ja.com

Spring Bootアプリケーションでの統合テスト用にEmbedded MongoDBをどのように構成しますか?

小さなREST APIを公開し、MongoDBのインスタンスからデータを取得するかなり単純なSpring Bootアプリケーションがあります。MongoDBインスタンスへのクエリは、Spring Dataベースのリポジトリを通過します。以下。

// Main application class
@EnableAutoConfiguration(exclude={MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
@ComponentScan
@Import(MongoConfig.class)
public class ProductApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class, args);
    }
}
// Product repository with Spring data
public interface ProductRepository extends MongoRepository<Product, String> {

    Page<Product> findAll(Pageable pageable);

    Optional<Product> findByLineNumber(String lineNumber);
}
// Configuration for "live" connections
@Configuration
public class MongoConfig {

    @Value("${product.mongo.Host}")
    private String mongoHost;

    @Value("${product.mongo.port}")
    private String mongoPort;

    @Value("${product.mongo.database}")
    private String mongoDatabase;

    @Bean(name="mongoClient")
    public MongoClient mongoClient() throws IOException {
        return new MongoClient(mongoHost, Integer.parseInt(mongoPort));
    }

    @Autowired
    @Bean(name="mongoDbFactory")
    public MongoDbFactory mongoDbFactory(MongoClient mongoClient) {
        return new SimpleMongoDbFactory(mongoClient, mongoDatabase);
    }

    @Autowired
    @Bean(name="mongoTemplate")
    public MongoTemplate mongoTemplate(MongoClient mongoClient) {
        return new MongoTemplate(mongoClient, mongoDatabase);
    }
}
@Configuration
@EnableMongoRepositories
public class EmbeddedMongoConfig {

    private static final String DB_NAME = "integrationTest";
    private static final int DB_PORT = 12345;
    private static final String DB_Host = "localhost";
    private static final String DB_COLLECTION = "products";

    private MongodExecutable mongodExecutable = null;

    @Bean(name="mongoClient")
    public MongoClient mongoClient() throws IOException {
        // Lots of calls here to de.flapdoodle.embed.mongo code base to 
        // create an embedded db and insert some JSON data
    }

    @Autowired
    @Bean(name="mongoDbFactory")
    public MongoDbFactory mongoDbFactory(MongoClient mongoClient) {
        return new SimpleMongoDbFactory(mongoClient, DB_NAME);
    }

    @Autowired
    @Bean(name="mongoTemplate")
    public MongoTemplate mongoTemplate(MongoClient mongoClient) {
        return new MongoTemplate(mongoClient, DB_NAME);
    }

    @PreDestroy
    public void shutdownEmbeddedMongoDB() {
        if (this.mongodExecutable != null) {
            this.mongodExecutable.stop();
        }
    }
}
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestProductApplication.class)
@IntegrationTest
@WebAppConfiguration
public class WtrProductApplicationTests {

    @Test
    public void contextLoads() {
        // Tests empty for now
    }

}
@EnableAutoConfiguration(exclude={MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
@ComponentScan
@Import(EmbeddedMongoConfig.class)
public class TestProductApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestProductApplication.class, args);
    }
}

したがって、ここでのアイデアは、統合テスト(現時点では空)を組み込みのmongoインスタンスに接続し、「ライブ」インスタンスに接続しないようにすることです。ただし、機能しません。 Mongoの「ライブ」インスタンスに接続しているテストを確認できます。それをシャットダウンすると、Mongoのライブインスタンスに接続しようとしているため、ビルドが失敗します。これがなぜだれか知っていますか?埋め込みインスタンスに接続するテストを取得するにはどうすればよいですか?

24
Jon

[〜#〜] edit [〜#〜]magiccrafter's answer Spring Boot 1.3+の場合、EmbeddedMongoAutoConfiguration

何らかの理由で使用できない場合は、読み続けてください。


テストクラス:

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(classes = {
        Application.class, 
        TestMongoConfig.class // <--- Don't forget THIS
    })
    public class GameRepositoryTest {

        @Autowired
        private GameRepository gameRepository;

        @Test
        public void shouldCreateGame() {
            Game game = new Game(null, "Far Cry 3");
            Game gameCreated = gameRepository.save(game);
            assertEquals(gameCreated.getGameId(), gameCreated.getGameId());
            assertEquals(game.getName(), gameCreated.getName());
        }

    } 

シンプルなMongoDBリポジトリ:

public interface GameRepository extends MongoRepository<Game, String>     {

    Game findByName(String name);
}

MongoDBテスト構成:

import com.mongodb.Mongo;
import com.mongodb.MongoClientOptions;
import de.flapdoodle.embed.mongo.MongodExecutable;
import de.flapdoodle.embed.mongo.MongodProcess;
import de.flapdoodle.embed.mongo.MongodStarter;
import de.flapdoodle.embed.mongo.config.IMongodConfig;
import de.flapdoodle.embed.mongo.config.MongodConfigBuilder;
import de.flapdoodle.embed.mongo.config.Net;
import de.flapdoodle.embed.mongo.distribution.Version;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import Java.io.IOException;

@Configuration
public class TestMongoConfig {

    @Autowired
    private MongoProperties properties;

    @Autowired(required = false)
    private MongoClientOptions options;

    @Bean(destroyMethod = "close")
    public Mongo mongo(MongodProcess mongodProcess) throws IOException {
        Net net = mongodProcess.getConfig().net();
        properties.setHost(net.getServerAddress().getHostName());
        properties.setPort(net.getPort());
        return properties.createMongoClient(this.options);
    }

    @Bean(destroyMethod = "stop")
    public MongodProcess mongodProcess(MongodExecutable mongodExecutable) throws IOException {
        return mongodExecutable.start();
    }

    @Bean(destroyMethod = "stop")
    public MongodExecutable mongodExecutable(MongodStarter mongodStarter, IMongodConfig iMongodConfig) throws IOException {
        return mongodStarter.prepare(iMongodConfig);
    }

    @Bean
    public IMongodConfig mongodConfig() throws IOException {
        return new MongodConfigBuilder().version(Version.Main.PRODUCTION).build();
    }

    @Bean
    public MongodStarter mongodStarter() {
        return MongodStarter.getDefaultInstance();
    }

}

pom.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
        <dependency>
            <groupId>de.flapdoodle.embed</groupId>
            <artifactId>de.flapdoodle.embed.mongo</artifactId>
            <version>1.48.0</version>
            <scope>test</scope>
        </dependency>
17
cahen

Spring Bootバージョン1.3以降、すぐに使用できるEmbeddedMongoAutoConfigurationクラスがあります。これは、設定ファイルを作成する必要がまったくなく、変更が必要な場合でもできることを意味します。

組み込みMongoDBの自動構成が追加されました。 de.flapdoodle.embed:de.flapdoodle.embed.mongoへの依存関係は、開始するために必要なものすべてです。使用するMongoのバージョンなどの構成は、application.propertiesを介して制御できます。詳細については、ドキュメントを参照してください。 ( スプリングブートリリースノート

Application.propertiesファイルに追加する必要がある最も基本的で重要な構成は次のとおりです。
spring.data.mongodb.port=0(0は、無料のものからランダムに選択されることを意味します)

詳細を確認するには: Spring Boot Docs MongoDb

34
magiccrafter

前の回答を完了します

pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.3.2.RELEASE</version>
</parent>
 ...
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
    <dependency>
        <groupId>de.flapdoodle.embed</groupId>
        <artifactId>de.flapdoodle.embed.mongo</artifactId>
        <version>${embedded-mongo.version}</version>
    </dependency>

MongoConfig

@Configuration
@EnableAutoConfiguration(exclude = { EmbeddedMongoAutoConfiguration.class })
public class MongoConfig{
}
5
panser

バージョン1.5.7では、これだけを使用します。

@RunWith(SpringRunner.class)
@DataMongoTest
public class UserRepositoryTests {

    @Autowired
    UserRepository repository;

    @Before
    public void setUp() {

        User user = new User();

        user.setName("test");
        repository.save(user);
    }

    @Test
    public void findByName() {
        List<User> result = repository.findByName("test");
        assertThat(result).hasSize(1).extracting("name").contains("test");
    }

}

そして

        <dependency>
            <groupId>de.flapdoodle.embed</groupId>
            <artifactId>de.flapdoodle.embed.mongo</artifactId>
        </dependency>
5
Nataniel Paiva

@ComponentScan。デフォルトでは、

特定のパッケージが定義されていない場合、このアノテーションを持つクラスのパッケージからスキャンが行われます。 ( @ ComponentScan Javadoc

したがって、TestProductApplication構成とProductApplication構成が両方とも同じパッケージにある場合、SpringがProductApplication構成をコンポーネントスキャンして使用している可能性があります。

さらに、テストMongo Beanを「テスト」または「ローカル」プロファイルに配置し、テストクラスで @ ActiveProfiles アノテーションを使用して、テスト/ローカルプロファイルを有効にすることをお勧めします。

3
FGreg