Produktverwaltung: Unit-Tests für Service erfolgreich hinzugefügt
parent
57028fba23
commit
a29c99d9e8
|
|
@ -0,0 +1,8 @@
|
|||
[ {
|
||||
"produktId" : "P-0001",
|
||||
"bezeichnung" : "M6 Schraube",
|
||||
"einzelpreisNetto" : 10.50,
|
||||
"mwstSatz" : "NORMAL",
|
||||
"beschreibung" : "Beschreibung",
|
||||
"kategorie" : "Werkzeug"
|
||||
} ]
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package de.hsmannheim.faktura.produkt;
|
||||
|
||||
public enum MwstSatz {
|
||||
|
||||
NORMAL,
|
||||
ERMAESSIGT
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
package de.hsmannheim.faktura.produkt;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class Produkt {
|
||||
|
||||
private String produktId;
|
||||
private String bezeichnung;
|
||||
private BigDecimal einzelpreisNetto;
|
||||
private MwstSatz mwstSatz;
|
||||
private String beschreibung;
|
||||
private String kategorie;
|
||||
|
||||
public Produkt() {
|
||||
|
||||
}
|
||||
|
||||
public Produkt(String produktId, String bezeichnung, BigDecimal einzelpreisNetto,
|
||||
MwstSatz mwstSatz, String beschreibung, String kategorie) {
|
||||
this.produktId = produktId;
|
||||
this.bezeichnung = bezeichnung;
|
||||
this.einzelpreisNetto = einzelpreisNetto;
|
||||
this.mwstSatz = mwstSatz;
|
||||
this.beschreibung = beschreibung;
|
||||
this.kategorie = kategorie;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// Getter und Setter
|
||||
// ==========================================
|
||||
|
||||
public String getProduktId() {
|
||||
return produktId;
|
||||
}
|
||||
|
||||
public void setProduktId(String produktId) {
|
||||
this.produktId = produktId;
|
||||
}
|
||||
|
||||
public String getBezeichnung() {
|
||||
return bezeichnung;
|
||||
}
|
||||
|
||||
public void setBezeichnung(String bezeichnung) {
|
||||
this.bezeichnung = bezeichnung;
|
||||
}
|
||||
|
||||
public BigDecimal getEinzelpreisNetto() {
|
||||
return einzelpreisNetto;
|
||||
}
|
||||
|
||||
public void setEinzelpreisNetto(BigDecimal einzelpreisNetto) {
|
||||
this.einzelpreisNetto = einzelpreisNetto;
|
||||
}
|
||||
|
||||
public MwstSatz getMwstSatz() {
|
||||
return mwstSatz;
|
||||
}
|
||||
|
||||
public void setMwstSatz(MwstSatz mwstSatz) {
|
||||
this.mwstSatz = mwstSatz;
|
||||
}
|
||||
|
||||
public String getBeschreibung() {
|
||||
return beschreibung;
|
||||
}
|
||||
|
||||
public void setBeschreibung(String beschreibung) {
|
||||
this.beschreibung = beschreibung;
|
||||
}
|
||||
|
||||
public String getKategorie() {
|
||||
return kategorie;
|
||||
}
|
||||
|
||||
public void setKategorie(String kategorie) {
|
||||
this.kategorie = kategorie;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Produkt{" +
|
||||
"produktId='" + produktId + '\'' +
|
||||
", bezeichnung='" + bezeichnung + '\'' +
|
||||
", einzelpreisNetto=" + einzelpreisNetto +
|
||||
", mwstSatz=" + mwstSatz +
|
||||
", kategorie='" + kategorie + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
package de.hsmannheim.faktura.produkt.repository;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import de.hsmannheim.faktura.produkt.Produkt;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
public class ProduktRepository {
|
||||
|
||||
|
||||
private static final String FILE_PATH = "./data/products.json";
|
||||
private final ObjectMapper objectMapper;
|
||||
private List<Produkt> cache;
|
||||
|
||||
public ProduktRepository() {
|
||||
this.objectMapper = new ObjectMapper();
|
||||
this.objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
|
||||
this.cache = new ArrayList<>();
|
||||
|
||||
|
||||
loadData();
|
||||
}
|
||||
|
||||
|
||||
public List<Produkt> findAll() {
|
||||
return new ArrayList<>(cache);
|
||||
}
|
||||
|
||||
|
||||
public Optional<Produkt> findById(String produktId) {
|
||||
return cache.stream()
|
||||
.filter(p -> p.getProduktId().equals(produktId))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public void save(Produkt product) {
|
||||
|
||||
Optional<Produkt> existingProduct = findById(product.getProduktId());
|
||||
|
||||
if (existingProduct.isPresent()) {
|
||||
int index = cache.indexOf(existingProduct.get());
|
||||
cache.set(index, product);
|
||||
} else {
|
||||
cache.add(product);
|
||||
}
|
||||
|
||||
|
||||
saveData();
|
||||
}
|
||||
|
||||
|
||||
public boolean deleteById(String produktId) {
|
||||
boolean removed = cache.removeIf(p -> p.getProduktId().equals(produktId));
|
||||
if (removed) {
|
||||
saveData();
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
|
||||
private void loadData() {
|
||||
File file = new File(FILE_PATH);
|
||||
|
||||
|
||||
if (!file.exists()) {
|
||||
this.cache = new ArrayList<>();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.cache = objectMapper.readValue(file, new TypeReference<List<Produkt>>() {});
|
||||
} catch (IOException e) {
|
||||
System.err.println("Fehler beim Laden der Produktdaten: " + e.getMessage());
|
||||
|
||||
this.cache = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void saveData() {
|
||||
File file = new File(FILE_PATH);
|
||||
|
||||
File directory = file.getParentFile();
|
||||
if (directory != null && !directory.exists()) {
|
||||
directory.mkdirs();
|
||||
}
|
||||
|
||||
try {
|
||||
objectMapper.writeValue(file, cache);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Fehler beim Speichern der Produktdaten: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package de.hsmannheim.faktura.produkt.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import de.hsmannheim.faktura.produkt.Produkt;
|
||||
import de.hsmannheim.faktura.produkt.repository.ProduktRepository;
|
||||
|
||||
|
||||
public class ProduktService {
|
||||
|
||||
private final ProduktRepository produktRepository;
|
||||
|
||||
public ProduktService(ProduktRepository produktRepository) {
|
||||
this.produktRepository = produktRepository;
|
||||
}
|
||||
|
||||
|
||||
public List<Produkt> getAllProducts() {
|
||||
return produktRepository.findAll();
|
||||
}
|
||||
|
||||
|
||||
public Optional<Produkt> getProductById(String produktId) {
|
||||
return produktRepository.findById(produktId);
|
||||
}
|
||||
|
||||
|
||||
public void saveProduct(Produkt product) {
|
||||
if (product == null) {
|
||||
throw new IllegalArgumentException("Das Produkt darf nicht null sein.");
|
||||
}
|
||||
|
||||
if (product.getEinzelpreisNetto() == null || product.getEinzelpreisNetto().compareTo(BigDecimal.ZERO) < 0) {
|
||||
throw new IllegalArgumentException("Anforderung F-SH-PV-06 verletzt: Der Einzelpreis Netto darf nicht negativ sein.");
|
||||
}
|
||||
|
||||
if (product.getProduktId() == null || product.getProduktId().trim().isEmpty()) {
|
||||
|
||||
product.setProduktId("PROD-" + java.util.UUID.randomUUID().toString().substring(0, 8));
|
||||
}
|
||||
|
||||
produktRepository.save(product);
|
||||
}
|
||||
|
||||
public boolean deleteProduct(String produktId) {
|
||||
if (produktId == null || produktId.trim().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return produktRepository.deleteById(produktId);
|
||||
}
|
||||
|
||||
public List<Produkt> searchProducts(String query) {
|
||||
if (query == null || query.trim().isEmpty()) {
|
||||
return getAllProducts();
|
||||
}
|
||||
String lowerQuery = query.toLowerCase();
|
||||
return getAllProducts().stream()
|
||||
.filter(p -> p.getBezeichnung() != null && p.getBezeichnung().toLowerCase().contains(lowerQuery))
|
||||
.collect(java.util.stream.Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package de.hsmannheim.faktura.produkt.service;
|
||||
|
||||
import de.hsmannheim.faktura.produkt.Produkt;
|
||||
import de.hsmannheim.faktura.produkt.MwstSatz;
|
||||
import de.hsmannheim.faktura.produkt.repository.ProduktRepository;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class ProduktServiceTest {
|
||||
|
||||
private ProduktService produktService;
|
||||
private ProduktRepository produktRepository;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
produktRepository = new ProduktRepository();
|
||||
produktService = new ProduktService(produktRepository);
|
||||
|
||||
// Cache leeren, damit alte JSON-Einträge die Tests nicht verfälschen
|
||||
for (Produkt p : produktRepository.findAll()) {
|
||||
produktRepository.deleteById(p.getProduktId());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveValidProduct() {
|
||||
Produkt valid = new Produkt("P-0001", "M6 Schraube", new BigDecimal("10.50"), MwstSatz.NORMAL, "Beschreibung", "Werkzeug");
|
||||
assertDoesNotThrow(() -> produktService.saveProduct(valid));
|
||||
assertTrue(produktService.getProductById("P-0001").isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNegativePriceRejection() {
|
||||
// AC-SH-PV-01: Preis kleiner als 0.00 muss abgelehnt werden
|
||||
Produkt invalidProduct = new Produkt("P-9999", "Testprodukt", new BigDecimal("-1.00"), MwstSatz.NORMAL, "Test", "Test");
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> produktService.saveProduct(invalidProduct));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchCaseInsensitive() {
|
||||
// AC-SH-PV-03: Suchtest für Groß-/Kleinschreibung
|
||||
Produkt p1 = new Produkt("P-0001", "M6 Schraube", new BigDecimal("1.00"), MwstSatz.NORMAL, "", "");
|
||||
Produkt p2 = new Produkt("P-0002", "M8 SCHRAUBE", new BigDecimal("2.00"), MwstSatz.NORMAL, "", "");
|
||||
|
||||
produktService.saveProduct(p1);
|
||||
produktService.saveProduct(p2);
|
||||
|
||||
List<Produkt> results = produktService.searchProducts("schraube");
|
||||
assertEquals(2, results.size());
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue