1. Übersicht
In diesem Tutorial erfahren wir, wie Sie die eingebettete MongoDB-Lösung von Flapdoodle zusammen mit Spring Boot verwenden, um MongoDB-Integrationstests reibungslos auszuführen.
MongoDB ist eine beliebte NoSQL-Dokumentendatenbank . Dank der hohen Skalierbarkeit, des integrierten Shardings und des hervorragenden Community-Supports wird es oft als „das bezeichnet NoSQL-Speicher“ von vielen Entwicklern.
Wie bei jeder anderen Persistenztechnologie ist es wichtig, die Datenbankintegration mit dem Rest unserer Anwendung einfach testen zu können . Glücklicherweise ermöglicht uns Spring Boot das einfache Schreiben dieser Art von Tests.
2. Maven-Abhängigkeiten
Zuerst richten wir das übergeordnete Maven für unser Boot-Projekt ein.
Dank der übergeordneten müssen wir die Version nicht für jede Maven-Abhängigkeit manuell definieren .
Wir werden natürlich Spring Boot verwenden:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.1</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
Die neueste Boot-Version finden Sie hier.
Da wir Spring Boot Parent hinzugefügt haben, können wir erforderliche Abhängigkeiten hinzufügen, ohne ihre Versionen anzugeben:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
spring-boot-starter-data-mongodb aktiviert die Spring-Unterstützung für MongoDB:
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>test</scope>
</dependency>
de.flapdoodle.embed.mongo bietet eingebettete MongoDB für Integrationstests.
3. Testen Sie mit eingebettetem MongoDB
Dieser Abschnitt behandelt zwei Szenarien:Spring Boot-Test und manueller Test.
3.1. Spring-Boot-Test
Nach dem Hinzufügen von de.flapdoodle.embed.mongo Abhängigkeit Spring Boot versucht automatisch, die eingebettete MongoDB herunterzuladen und zu starten beim Ausführen von Tests.
Das Paket wird für jede Version nur einmal heruntergeladen, sodass nachfolgende Tests viel schneller ablaufen.
Zu diesem Zeitpunkt sollten wir in der Lage sein, den Beispiel-JUnit-5-Integrationstest zu starten und zu bestehen:
@DataMongoTest
@ExtendWith(SpringExtension.class)
public class MongoDbSpringIntegrationTest {
@DisplayName("given object to save"
+ " when save object using MongoDB template"
+ " then object is saved")
@Test
public void test(@Autowired MongoTemplate mongoTemplate) {
// given
DBObject objectToSave = BasicDBObjectBuilder.start()
.add("key", "value")
.get();
// when
mongoTemplate.save(objectToSave, "collection");
// then
assertThat(mongoTemplate.findAll(DBObject.class, "collection")).extracting("key")
.containsOnly("value");
}
}
Wie wir sehen können, wurde die eingebettete Datenbank automatisch von Spring gestartet, was auch in der Konsole protokolliert werden sollte:
...Starting MongodbExampleApplicationTests on arroyo with PID 10413...
3.2. Manueller Konfigurationstest
Spring Boot startet und konfiguriert automatisch die eingebettete Datenbank und fügt dann MongoTemplate ein Beispiel für uns. Manchmal müssen wir jedoch möglicherweise die eingebettete Mongo-Datenbank manuell konfigurieren (z. B. beim Testen einer bestimmten DB-Version).
Das folgende Snippet zeigt, wie wir die eingebettete MongoDB-Instanz manuell konfigurieren können. Dies entspricht in etwa dem vorherigen Spring-Test:
class ManualEmbeddedMongoDbIntegrationTest {
private static final String CONNECTION_STRING = "mongodb://%s:%d";
private MongodExecutable mongodExecutable;
private MongoTemplate mongoTemplate;
@AfterEach
void clean() {
mongodExecutable.stop();
}
@BeforeEach
void setup() throws Exception {
String ip = "localhost";
int port = 27017;
ImmutableMongodConfig mongodConfig = MongodConfig
.builder()
.version(Version.Main.PRODUCTION)
.net(new Net(ip, port, Network.localhostIsIPv6()))
.build();
MongodStarter starter = MongodStarter.getDefaultInstance();
mongodExecutable = starter.prepare(mongodConfig);
mongodExecutable.start();
mongoTemplate = new MongoTemplate(MongoClients.create(String.format(CONNECTION_STRING, ip, port)), "test");
}
@DisplayName("given object to save"
+ " when save object using MongoDB template"
+ " then object is saved")
@Test
void test() throws Exception {
// given
DBObject objectToSave = BasicDBObjectBuilder.start()
.add("key", "value")
.get();
// when
mongoTemplate.save(objectToSave, "collection");
// then
assertThat(mongoTemplate.findAll(DBObject.class, "collection")).extracting("key")
.containsOnly("value");
}
}
Beachten Sie, dass wir MongoTemplate schnell erstellen können Bean so konfiguriert, dass sie unsere manuell konfigurierte eingebettete Datenbank verwendet und sie im Spring-Container registriert, indem sie lediglich z. B. eine @TestConfiguration erstellt mit @Bean Methode, die new MongoTemplate(MongoClients.create(connectionString, „test“) zurückgibt .
Weitere Beispiele finden Sie im offiziellen GitHub-Repository von Flapdoodle.
3.3. Protokollierung
Wir können Protokollmeldungen für MongoDB konfigurieren, wenn Integrationstests ausgeführt werden, indem wir diese beiden Eigenschaften zu src/test/resources/application.propertes hinzufügen Datei:
logging.level.org.springframework.boot.autoconfigure.mongo.embedded
logging.level.org.mongodb
Um beispielsweise die Protokollierung zu deaktivieren, setzen wir die Werte einfach auf off :
logging.level.org.springframework.boot.autoconfigure.mongo.embedded=off
logging.level.org.mongodb=off
3.4. Verwendung einer echten Datenbank zur Produktion
Seit wir de.flapdoodle.embed.mongo hinzugefügt haben Abhängigkeit mit
Um eine eingebettete Datenbank außerhalb von Tests zu verwenden, können wir Spring-Profile verwenden, die den richtigen MongoClient registrieren (eingebettet oder Produktion) je nach aktivem Profil.
Außerdem müssen wir den Bereich der Produktionsabhängigkeit in
4. Kontroverse um eingebettete Tests
Die Verwendung einer eingebetteten Datenbank mag am Anfang wie eine großartige Idee aussehen. In der Tat ist dies ein guter Ansatz, wenn wir testen möchten, ob sich unsere Anwendung in folgenden Bereichen korrekt verhält:
- Objekt<->Dokumentenzuordnungskonfiguration
- Benutzerdefinierte Ereignis-Listener für den Persistenzlebenszyklus (siehe AbstractMongoEventListener )
- Die Logik jedes Codes, der direkt mit der Persistenzschicht arbeitet
Leider kann die Verwendung eines eingebetteten Servers nicht als „vollständiger Integrationstest“ betrachtet werden . Die eingebettete MongoDB von Flapdoodle ist kein offizielles MongoDB-Produkt. Daher können wir nicht sicher sein, dass es sich genau wie in der Produktionsumgebung verhält.
Wenn wir Kommunikationstests in der Umgebung so nah wie möglich an der Produktion ausführen möchten, ist eine bessere Lösung die Verwendung eines Umgebungscontainers wie Docker.
Um mehr über Docker zu erfahren, lesen Sie unseren vorherigen Artikel hier.