Cet examen pratique est conçu pour évaluer vos compétences en développement, tests unitaires, tests d'intégration, tests E2E (end-to-end) et en mise en œuvre d'outils de qualité du code comme SonarQube et JMeter. Vous travaillerez sur une application de location de voiture développée en Java avec Spring Boot. L'examen est divisé en plusieurs parties avec des objectifs clairs.
- Implémenter des tests unitaires, des tests avec mocks et spies, et des tests d'intégration pour une application existante.
- Ajouter deux nouvelles fonctionnalités selon le principe du Test-Driven Development (TDD) et écrire les tests nécessaires.
- Implémenter 3 scénarios E2E en utilisant Cucumber.
- Pluger SonarQube sur le projet et fournir un conteneur Docker pour l'exécuter localement.
- Créer un fichier
.jmxpour effectuer des tests de charge avec JMeter.
-
Prérequis logiciels :
- Java 11 ou plus récent
- Maven ou Gradle
- Docker (pour SonarQube)
- JMeter (pour les tests de charge)
-
Livrables attendus :
- Code source complet avec les tests unitaires, mocks, spies, et tests d'intégration.
- Code des deux nouvelles fonctionnalités avec leurs tests (TDD).
- Fichier
cucumber.featurepour les scénarios E2E. - Fichier Docker Compose pour exécuter SonarQube.
- Fichier
.jmxpour les tests de charge.
Les classes suivantes sont fournies. Vous devez écrire les tests unitaires, les tests avec mocks et spies, ainsi que les tests d'intégration.
package com.example.rental;
public class Car {
private String registrationNumber;
private String model;
private boolean available;
public Car(String registrationNumber, String model, boolean available) {
this.registrationNumber = registrationNumber;
this.model = model;
this.available = available;
}
public String getRegistrationNumber() {
return registrationNumber;
}
public String getModel() {
return model;
}
public boolean isAvailable() {
return available;
}
public void setAvailable(boolean available) {
this.available = available;
}
}package com.example.rental;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Repository
public class CarRepository {
private final List<Car> cars = new ArrayList<>();
public List<Car> getAllCars() {
return cars;
}
public Optional<Car> findByRegistrationNumber(String registrationNumber) {
return cars.stream()
.filter(car -> car.getRegistrationNumber().equals(registrationNumber))
.findFirst();
}
public void addCar(Car car) {
cars.add(car);
}
public void updateCar(Car car) {
cars.replaceAll(c -> c.getRegistrationNumber().equals(car.getRegistrationNumber()) ? car : c);
}
}package com.example.rental;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class CarRentalService {
@Autowired
private CarRepository carRepository;
public List<Car> getAllCars() {
return carRepository.getAllCars();
}
public boolean rentCar(String registrationNumber) {
Optional<Car> car = carRepository.findByRegistrationNumber(registrationNumber);
if (car.isPresent() && car.get().isAvailable()) {
car.get().setAvailable(false);
carRepository.updateCar(car.get());
return true;
}
return false;
}
public void returnCar(String registrationNumber) {
Optional<Car> car = carRepository.findByRegistrationNumber(registrationNumber);
car.ifPresent(c -> {
c.setAvailable(true);
carRepository.updateCar(c);
});
}
}package com.example.rental;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/cars")
public class CarController {
@Autowired
private CarRentalService carRentalService;
@GetMapping
public List<Car> getAllCars() {
return carRentalService.getAllCars();
}
@PostMapping("/rent/{registrationNumber}")
public boolean rentCar(@PathVariable String registrationNumber) {
return carRentalService.rentCar(registrationNumber);
}
@PostMapping("/return/{registrationNumber}")
public void returnCar(@PathVariable String registrationNumber) {
carRentalService.returnCar(registrationNumber);
}
}-
Tests unitaires :
- Écrire des tests unitaires pour chaque méthode des classes
CarRepositoryetCarRentalService. - Utiliser des mocks pour isoler les dépendances (par exemple, mocker
CarRepositorydansCarRentalService).
- Écrire des tests unitaires pour chaque méthode des classes
-
Tests avec spies :
- Ajouter des tests pour vérifier les interactions entre les différentes méthodes (par exemple, vérifier que
updateCarest bien appelée aprèsrentCar).
- Ajouter des tests pour vérifier les interactions entre les différentes méthodes (par exemple, vérifier que
-
Tests d'intégration :
- Écrire des tests pour les endpoints REST dans
CarController. - Utiliser MockMvc pour simuler les requêtes HTTP.
- Écrire des tests pour les endpoints REST dans
Ajoutez les deux fonctionnalités suivantes :
-
Ajouter une voiture :
- Endpoint
POST /cars/addpour ajouter une nouvelle voiture. - La voiture ne peut être ajoutée que si son numéro d'immatriculation est unique.
- Endpoint
-
Rechercher une voiture par modèle :
- Endpoint
GET /cars/search?model={model}pour rechercher toutes les voitures d'un modèle donné.
- Endpoint
-
Suivez les principes du Test-Driven Development (TDD) :
- Écrivez les tests avant d'implémenter les fonctionnalités.
- Testez les scénarios de succès et d'échec (par exemple, tentative d'ajouter une voiture avec un numéro d'immatriculation déjà existant).
-
Implémentez les fonctionnalités une fois les tests écrits.
Écrivez 3 scénarios de tests E2E pour l'application en utilisant Cucumber :
-
Scénario : Lister toutes les voitures disponibles
Given des voitures sont disponibles When je demande la liste des voitures Then toutes les voitures sont affichées
-
Scénario : Louer une voiture avec succès
Given une voiture est disponible When je loue cette voiture Then la voiture n'est plus disponible
-
Scénario : Retourner une voiture
Given une voiture est louée When je retourne cette voiture Then la voiture est marquée comme disponible
-
Pluger SonarQube :
- Ajoutez le plugin SonarQube dans votre projet Maven ou Gradle.
- Fournissez un fichier Docker Compose pour exécuter SonarQube localement.
Exemple de fichier
docker-compose.yml:version: "3" services: sonarqube: image: sonarqube:community container_name: sonarqube ports: - "9000:9000" environment: SONAR_ES_BOOTSTRAP_CHECKS_DISABLE: "true"
-
Fournissez un rapport SonarQube montrant la couverture des tests et les éventuels problèmes détectés.
-
Créez un fichier
.jmxpour exécuter une batterie de tests de charge :- Scénario 1 : 100 utilisateurs simultanés demandent la liste des voitures (
GET /cars). - Scénario 2 : 50 utilisateurs simultanés louent des voitures (
POST /cars/rent/{registrationNumber}). - Scénario 3 : 30 utilisateurs retournent des voitures (
POST /cars/return/{registrationNumber}).
- Scénario 1 : 100 utilisateurs simultanés demandent la liste des voitures (
-
Fournissez les métriques collectées (temps de réponse, taux d'erreur, etc.).
- Code source complet (tests unitaires, mocks, spies, intégration, TDD).
- Fichiers
.featurepour les scénarios Cucumber. - Rapport SonarQube.
- Fichier dockerfile and
docker-compose.yml(optional) pour SonarQube. - Fichier
.jmxpour les tests de charge. (optional)
- Documentation Spring Boot
- Mockito Documentation
- Cucumber Documentation
- SonarQube Documentation
- JMeter Documentation
Bonne chance pour cet examen ! 😊