J'ai une application Spring Boot assez simple qui expose une petite REST et récupère les données d'une instance de MongoDB. Les requêtes vers l'instance MongoDB passent par un référentiel basé sur Spring Data. Quelques bits clés de code au dessous de.
// 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);
}
}
L'idée ici est donc de faire en sorte que les tests d'intégration (vides pour le moment) se connectent à l'instance de mongo intégrée et non à l'instance "en direct". Mais ça ne marche pas. Je peux voir les tests se connectant à l'instance "en direct" de Mongo, et si je ferme cela, la construction échoue simplement car elle tente toujours de se connecter à l'instance en direct de Mongo. Quelqu'un sait pourquoi c'est comme cela? Comment puis-je obtenir les tests pour me connecter à l'instance intégrée?
[~ # ~] éditez [~ # ~] : voir réponse de magiccrafter pour Spring Boot 1.3+, en utilisant EmbeddedMongoAutoConfiguration
.
Si vous ne pouvez pas l'utiliser pour une raison quelconque, continuez à lire.
Classe de test:
@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());
}
}
Référentiel MongoDB simple:
public interface GameRepository extends MongoRepository<Game, String> {
Game findByName(String name);
}
Configuration du test 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>
Depuis Spring Boot version 1.3, il existe une classe EmbeddedMongoAutoConfiguration
qui sort de la boîte. Cela signifie que vous n'avez pas du tout besoin de créer un fichier de configuration et si vous voulez changer des choses, vous pouvez toujours.
La configuration automatique pour Embedded MongoDB a été ajoutée. Une dépendance à de.flapdoodle.embed: de.flapdoodle.embed.mongo est tout ce qui est nécessaire pour commencer. La configuration, telle que la version de Mongo à utiliser, peut être contrôlée via application.properties. Veuillez consulter la documentation pour plus d'informations. ( Notes de version Spring Boot )
La configuration la plus élémentaire et la plus importante à ajouter aux fichiers application.properties estspring.data.mongodb.port=0
(0 signifie qu'il sera sélectionné aléatoirement parmi les libres)
pour plus de détails, vérifiez: Spring Boot Docs MongoDb
Je vais compléter la réponse précédente
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{
}
Dans la version 1.5.7, utilisez simplement ceci:
@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");
}
}
Et
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
</dependency>
Assurez-vous d'être explicite avec votre @ComponentScan
. Par défaut,
Si des packages spécifiques ne sont pas définis, l'analyse se fera à partir du package de la classe avec cette annotation. ( @ ComponentScan Javadoc )
Par conséquent, si vos configurations TestProductApplication
et ProductApplication
sont toutes les deux dans le même package, il est possible que Spring analyse les composants de votre configuration ProductApplication
et les utilise.
De plus, je recommanderais de placer vos haricots Mongo de test dans un profil "test" ou "local" et d'utiliser l'annotation @ ActiveProfiles dans votre classe de test pour activer le profil test/local.