spring-boot
Test en botte de printemps
Recherche…
Comment tester une application Spring simple
Nous avons un exemple d'application d'amorçage Spring qui stocke les données utilisateur dans MongoDB et nous utilisons les services Rest pour récupérer les données.
Il y a d'abord une classe de domaine, c'est-à-dire POJO
@Document
public class User{
@Id
private String id;
private String name;
}
Un référentiel correspondant basé sur Spring Data MongoDB
public interface UserRepository extends MongoRepository<User, String> {
}
Puis notre contrôleur utilisateur
@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
}
Et enfin notre application Spring Boot
@SpringBootApplication
public class Application {
public static void main(String args[]){
SpringApplication.run(Application.class, args);
}
}
Si, disons que John Cena, The Rock et TripleHHH étaient les trois seuls utilisateurs de la base de données, une demande à / users donnerait la réponse suivante:
$ curl localhost:8080/users
[{"name":"John Cena","id":"1"},{"name":"The Rock","id":"2"},{"name":"TripleHHH","id":"3"}]
Maintenant, pour tester le code, nous allons vérifier que l'application fonctionne
@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);
}
}
Explication
- Comme pour tout autre test basé sur Spring, nous avons besoin de
SpringJUnit4ClassRunner
pourSpringJUnit4ClassRunner
un contexte d'application. - L'annotation
@SpringApplicationConfiguration
est similaire à l'annotation@ContextConfiguration
en ce sens qu'elle est utilisée pour spécifier le ou les contextes d'application à utiliser dans le test. En outre, il déclenchera la logique de lecture des configurations, propriétés et autres éléments spécifiques du démarrage du ressort. -
@WebAppConfiguration
doit être présent pour indiquer à Spring qu’unWebApplicationContext
doit être chargé pour le test. Il fournit également un attribut pour spécifier le chemin d'accès à la racine de l'application Web. -
@IntegrationTest
est utilisé pour indiquer à Spring Boot que le serveur Web intégré doit être démarré. En fournissant des paires nom-valeur séparées par des deux-points ou des équations, toutes les variables d'environnement peuvent être remplacées. Dans cet exemple, le"server.port:0"
remplacera le paramètre de port par défaut du serveur. Normalement, le serveur commence à utiliser le numéro de port spécifié, mais la valeur 0 a une signification particulière. Lorsqu'elle est définie sur 0, elle indique à Spring Boot d'analyser les ports de l'environnement hôte et de démarrer le serveur sur un port disponible aléatoire. Cela est utile si différents services occupent différents ports sur les machines de développement et le serveur de génération qui pourrait potentiellement entrer en collision avec le port de l'application, auquel cas l'application ne démarrera pas. Deuxièmement, si nous créons plusieurs tests d'intégration avec des contextes d'application différents, ils peuvent également entrer en conflit si les tests s'exécutent simultanément. - Nous avons accès au contexte de l’application et nous pouvons utiliser l’auto-activation pour injecter n'importe quel bean Spring.
- La valeur
@Value("${local.server.port}”)
sera résolue au numéro de port utilisé. - Nous créons des entités que nous pouvons utiliser pour la validation.
- La base de données MongoDB est effacée et réinitialisée pour chaque test afin de toujours valider par rapport à un état connu. L'ordre des tests n'étant pas défini, il est probable que le test testFetchAll () échoue s'il est exécuté après le test testDeletetripleHHH ().
- Nous demandons au Rest Assuré d'utiliser le bon port. C'est un projet open source qui fournit une DSL Java pour tester des services reposants.
- Les tests sont implémentés en utilisant Rest Assured. nous pouvons implémenter les tests en utilisant TestRestTemplate ou tout autre client http, mais j'utilise Rest Assured car nous pouvons écrire une documentation concise en utilisant RestDocs
Chargement de différents fichiers yaml [ou properties] ou remplacement de certaines propriétés
Lorsque nous utilisons @SpringApplicationConfiguration
il utilisera la configuration de application.yml
[propriétés] qui, dans certaines situations, n'est pas appropriée. Donc, pour remplacer les propriétés, nous pouvons utiliser l’annotation @TestPropertySource
.
@TestPropertySource(
properties = {
"spring.jpa.hibernate.ddl-auto=create-drop",
"liquibase.enabled=false"
}
)
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class ApplicationTest{
// ...
}
Nous pouvons utiliser l'attribut de propriétés de @TestPropertySource
pour remplacer les propriétés spécifiques souhaitées. Dans l' exemple ci - dessus , nous prépondérants propriété spring.jpa.hibernate.ddl-auto
pour create-drop
. Et liquibase.enabled
à false
.
Chargement d'un fichier yml différent
Si vous souhaitez charger un fichier yml différent pour le test, vous pouvez utiliser l'attribut locations sur @TestPropertySource
.
@TestPropertySource(locations="classpath:test.yml")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class ApplicationTest{
// ...
}
Options alternatives
Option 1:
Vous pouvez également charger un fichier yml différent en plaçant un fichier yml sur test > resource
répertoire de test > resource
Option 2:
Utiliser l'annotation @ActiveProfiles
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@ActiveProfiles("somename")
public class MyIntTest{
}
Vous pouvez voir que nous @ActiveProfiles
annotation @ActiveProfiles
et que nous passons le nom de fichier comme valeur.
Créez un fichier appelé application-somename.yml
et le test chargera ce fichier.