spring-boot
Testen im Spring Boot
Suche…
So testen Sie eine einfache Spring-Boot-Anwendung
Wir haben ein Beispiel für eine Spring-Boot-Anwendung, die Benutzerdaten in MongoDB speichert, und wir verwenden Rest-Services, um Daten abzurufen
Zunächst gibt es eine Domänenklasse, z. B. POJO
@Document
public class User{
@Id
private String id;
private String name;
}
Ein entsprechendes Repository basierend auf Spring Data MongoDB
public interface UserRepository extends MongoRepository<User, String> {
}
Dann unser User Controller
@RestController
class UserController {
@Autowired
private UserRepository repository;
@RequestMapping("/users")
List<User> users() {
return repository.findAll();
}
@RequestMapping(value = "/Users/{id}", method = RequestMethod.DELETE)
@ResponseStatus(HttpStatus.NO_CONTENT)
void delete(@PathVariable("id") String id) {
repository.delete(id);
}
// more controller methods
}
Und zum Schluss noch unsere Spring Boot Applikation
@SpringBootApplication
public class Application {
public static void main(String args[]){
SpringApplication.run(Application.class, args);
}
}
Wenn beispielsweise John Cena, The Rock und TripleHHH die einzigen drei Benutzer in der Datenbank wären, würde eine Anfrage an / Benutzer die folgende Antwort geben:
$ curl localhost:8080/users
[{"name":"John Cena","id":"1"},{"name":"The Rock","id":"2"},{"name":"TripleHHH","id":"3"}]
Um den Code zu testen, überprüfen wir nun, ob die Anwendung funktioniert
@RunWith(SpringJUnit4ClassRunner.class) // 1
@SpringApplicationConfiguration(classes = Application.class) // 2
@WebAppConfiguration // 3
@IntegrationTest("server.port:0") // 4
public class UserControllerTest {
@Autowired // 5
UserRepository repository;
User cena;
User rock;
User tripleHHH;
@Value("${local.server.port}") // 6
int port;
@Before
public void setUp() {
// 7
cena = new User("John Cena");
rock = new User("The Rock");
tripleHHH = new User("TripleHH");
// 8
repository.deleteAll();
repository.save(Arrays.asList(cena, rock, tripleHHH));
// 9
RestAssured.port = port;
}
// 10
@Test
public void testFetchCena() {
String cenaId = cena.getId();
when().
get("/Users/{id}", cenaId).
then().
statusCode(HttpStatus.SC_OK).
body("name", Matchers.is("John Cena")).
body("id", Matchers.is(cenaId));
}
@Test
public void testFetchAll() {
when().
get("/users").
then().
statusCode(HttpStatus.SC_OK).
body("name", Matchers.hasItems("John Cena", "The Rock", "TripleHHH"));
}
@Test
public void testDeletetripleHHH() {
String tripleHHHId = tripleHHH.getId();
when()
.delete("/Users/{id}", tripleHHHId).
then().
statusCode(HttpStatus.SC_NO_CONTENT);
}
}
Erläuterung
- Wie bei jedem anderen Spring-basierten Test benötigen wir den
SpringJUnit4ClassRunner
damit ein Anwendungskontext erstellt wird. - Die Annotation
@SpringApplicationConfiguration
ähnelt der Annotation@ContextConfiguration
Sie wird verwendet, um anzugeben, welche Anwendungskontexte im Test verwendet werden sollen. Darüber hinaus wird eine Logik zum Lesen von Spring Boot-spezifischen Konfigurationen, Eigenschaften usw. ausgelöst. -
@WebAppConfiguration
muss vorhanden sein, um Spring mitzuteilen, dass einWebApplicationContext
für den Test geladen werden soll. Außerdem enthält es ein Attribut zum Angeben des Pfads zum Stammverzeichnis der Webanwendung. -
@IntegrationTest
Spring Boot mit, dass der eingebettete Webserver gestartet werden soll. Durch Angabe von Doppelpunkt- oder gleichwertigen Namen / Wert-Paaren kann jede Umgebungsvariable überschrieben werden. In diesem Beispiel überschreibt"server.port:0"
die Standardporteinstellung des Servers. Normalerweise verwendet der Server die angegebene Portnummer, der Wert 0 hat jedoch eine besondere Bedeutung. Wenn der Wert 0 ist, wird Spring Boot angewiesen, die Ports in der Hostumgebung zu scannen und den Server an einem beliebigen verfügbaren Port zu starten. Dies ist nützlich, wenn verschiedene Dienste auf den Entwicklungsmaschinen und dem Build-Server unterschiedliche Ports belegen, die möglicherweise mit dem Anwendungsport kollidieren. In diesem Fall wird die Anwendung nicht gestartet. Zweitens: Wenn wir mehrere Integrationstests mit unterschiedlichen Anwendungskontexten erstellen, können diese auch kollidieren, wenn die Tests gleichzeitig ausgeführt werden. - Wir haben Zugriff auf den Anwendungskontext und können mithilfe von Autowiring Springbeans injizieren.
- Der
@Value("${local.server.port}”)
wird in die tatsächlich verwendete Portnummer aufgelöst. - Wir erstellen einige Entitäten, die wir zur Validierung verwenden können.
- Die MongoDB-Datenbank wird für jeden Test gelöscht und neu initialisiert, sodass immer ein bekannter Zustand geprüft wird. Da die Reihenfolge der Tests nicht definiert ist, besteht die Möglichkeit, dass der Test testFetchAll () fehlschlägt, wenn er nach dem Test testDeletetripleHHH () ausgeführt wird.
- Wir weisen Rest Assured an, den richtigen Port zu verwenden. Es handelt sich um ein Open Source-Projekt, das eine Java-DSL zum Testen unruhiger Dienste bereitstellt
- Tests werden mithilfe von Rest Assured implementiert. Wir können die Tests mithilfe des TestRestTemplate oder eines anderen http-Clients implementieren. Ich verwende jedoch Rest Assured, da wir mit RestDocs eine präzise Dokumentation schreiben können
Laden verschiedener yaml-Dateien [oder Eigenschaften] oder Überschreiben einiger Eigenschaften
Wenn wir @SpringApplicationConfiguration
, wird die Konfiguration von application.yml
[Eigenschaften] verwendet, was in bestimmten Situationen nicht angemessen ist. @TestPropertySource
die Eigenschaften zu überschreiben, können wir die Annotation @TestPropertySource
.
@TestPropertySource(
properties = {
"spring.jpa.hibernate.ddl-auto=create-drop",
"liquibase.enabled=false"
}
)
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class ApplicationTest{
// ...
}
Wir können das properties- Attribut von @TestPropertySource
, um die @TestPropertySource
spezifischen Eigenschaften zu überschreiben. In obigem Beispiel überschreiben wir die Eigenschaft spring.jpa.hibernate.ddl-auto
, create-drop
zu create-drop
. Und liquibase.enabled
auf false
.
Laden einer anderen Yml-Datei
Wenn Sie verschiedene Yml- Dateien vollständig zum Testen laden möchten, können Sie das Attribut location auf @TestPropertySource
.
@TestPropertySource(locations="classpath:test.yml")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class ApplicationTest{
// ...
}
Alternativ Optionen
Option 1:
Sie können auch eine andere Yml- Datei laden, indem Sie eine Yml- Datei in das Verzeichnis test > resource
Option 2:
Verwenden der Annotation @ActiveProfiles
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@ActiveProfiles("somename")
public class MyIntTest{
}
Sie können sehen, dass wir @ActiveProfiles
Annotation verwenden, und wir übergeben den Namen als Wert.
Erstellen Sie eine Datei namens application-somename.yml
und der Test lädt diese Datei.