Application web ASP.NET Core (net 9.0) de type boutique en ligne ("OpenClassrooms shop") permettant de :
- Afficher une liste de produits
- Ajouter des produits au panier
- Passer une commande
- Changer la langue de l'interface (Anglais, Français, Espagnol)
| Indicateur | Avant | Après |
|---|---|---|
| Compilation | ✅ 0 erreur | ✅ 0 erreur |
| Tests unitaires | ❌ 1/8 réussi | ✅ 8/8 réussis |
| Panier (AddItem) | ❌ Ne fonctionne pas | ✅ Fonctionne |
| Panier (Total/Moyenne) | ❌ Toujours 0 | ✅ Calculé correctement |
| Ajout au panier (bouton) | ❌ Aucun effet | ✅ Fonctionne |
| Décrément du stock | ❌ Jamais décrémenté | ✅ Fonctionne |
| Changement de langue | ❌ Aucun effet | ✅ Fonctionne |
Problème racine : La méthode GetCartLineList() retournait new List<CartLine>() à chaque appel — une nouvelle liste vide à chaque fois. Aucun produit n'était donc jamais conservé dans le panier.
Correction : Ajout d'un champ privé _cartLines persistant pour toute la durée de vie de l'instance :
// AVANT (bug) :
private List<CartLine> GetCartLineList()
{
return new List<CartLine>(); // ← nouvelle liste vide à chaque appel !
}
// APRÈS (corrigé) :
private readonly List<CartLine> _cartLines = new List<CartLine>();
private List<CartLine> GetCartLineList() => _cartLines;TODOs implémentés :
Ajoute un produit au panier. Si le produit est déjà présent (même Id), sa quantité est incrémentée ; sinon, une nouvelle ligne est créée.
CartLine existingLine = _cartLines.FirstOrDefault(l => l.Product.Id == product.Id);
if (existingLine == null)
_cartLines.Add(new CartLine { ... });
else
existingLine.Quantity += quantity;Somme de prix × quantité pour chaque ligne du panier.
return _cartLines.Sum(l => l.Product.Price * l.Quantity);Valeur totale divisée par le nombre total d'articles.
return GetTotalValue() / _cartLines.Sum(l => l.Quantity);Recherche un produit dans les lignes du panier par son identifiant.
return _cartLines.FirstOrDefault(l => l.Product.Id == productId)?.Product;Recherche un produit dans l'inventaire par son identifiant via le repository.
return _productRepository.GetAllProducts().FirstOrDefault(p => p.Id == id);Impact bug : Sans cette implémentation,
CartController.AddToCart()retournait toujoursnull, rendant le bouton "Ajouter au panier" totalement non fonctionnel.
Parcourt les lignes du panier et décrémente le stock de chaque produit commandé.
foreach (CartLine line in cart.Lines)
{
_productRepository.UpdateProductStocks(line.Product.Id, line.Quantity);
}Mappe le nom de la langue sélectionnée vers le code de culture correspondant.
switch (language)
{
case "French": return "fr";
case "Spanish": return "es";
default: return "en"; // Anglais par défaut
}Problème : Le champ _products est static (partagé entre toutes les instances), mais le constructeur le réinitialisait à chaque new ProductRepository(), effaçant les modifications de stock déjà effectuées.
Correction : Ajout d'une vérification null pour n'initialiser les données qu'une seule fois :
// AVANT (bug) :
public ProductRepository()
{
_products = new List<Product>(); // ← réinitialise le stock à chaque fois !
GenerateProductData();
}
// APRÈS (corrigé) :
public ProductRepository()
{
if (_products == null) // n'initialise que si pas encore fait
{
_products = new List<Product>();
GenerateProductData();
}
}Impact : Le test
UpdateProductQuantitiesvérifie que le stock diminue correctement sur plusieurs passages de commande. Sans ce correctif, le stock était remis à zéro entre chaque appel.
P2FixAnAppDotNetCode/
├── Program.cs ← Point d'entrée (ne pas modifier)
├── Startup.cs ← Injection de dépendances + localisation
├── Controllers/
│ ├── CartController.cs ← Gestion du panier (ne pas modifier)
│ ├── OrderController.cs ← Gestion des commandes (ne pas modifier)
│ ├── ProductController.cs ← Affichage des produits (ne pas modifier)
│ └── LanguageController.cs ← Changement de langue (ne pas modifier)
├── Models/
│ ├── Cart.cs ← ✏️ MODIFIÉ
│ ├── ICart.cs ← Interface (ne pas modifier)
│ ├── Product.cs ← Modèle de données (ne pas modifier)
│ ├── Order.cs ← Modèle de données (ne pas modifier)
│ ├── Services/
│ │ ├── ProductService.cs ← ✏️ MODIFIÉ
│ │ ├── LanguageService.cs ← ✏️ MODIFIÉ
│ │ └── OrderService.cs ← Déjà fonctionnel (ne pas modifier)
│ └── Repositories/
│ ├── ProductRepository.cs ← ✏️ MODIFIÉ (correctif constructeur)
│ └── OrderRepository.cs ← (ne pas modifier)
├── Views/ ← Toutes les vues (ne pas modifier)
└── Resources/ ← Fichiers de traduction .resx (ne pas modifier)
P2FixAnAppDotNetCode.Tests/
├── CartTests.cs ← 4 tests (tous réussis ✅)
├── ProductServiceTests.cs ← 3 tests (tous réussis ✅)
└── LanguageServiceTests.cs ← 1 test (réussi ✅)
Série de tests réussie.
Nombre total de tests : 8
Réussi(s) : 8
Durée totale : 1,456 Secondes
| Test | Classe | Statut |
|---|---|---|
AddItemInCart |
CartTests | ✅ Réussi |
GetTotalValue |
CartTests | ✅ Réussi |
GetAverageValue |
CartTests | ✅ Réussi |
FindProductInCartLines |
CartTests | ✅ Réussi |
Product (type retour) |
ProductServiceTests | ✅ Réussi |
GetProductById |
ProductServiceTests | ✅ Réussi |
UpdateProductQuantities |
ProductServiceTests | ✅ Réussi |
SetCulture |
LanguageServiceTests | ✅ Réussi |
# Compiler
dotnet build P2FixAnAppDotNetCode.sln
# Lancer les tests
dotnet test P2FixAnAppDotNetCode.Tests/P2FixAnAppDotNetCode.Tests.csproj
# Démarrer l'application web
cd P2FixAnAppDotNetCode
dotnet runL'application sera accessible sur http://localhost:5000 (ou le port indiqué dans la console).