mirror of
https://github.com/st-tu-dresden-praktikum/swt23w23
synced 2024-07-19 21:04:36 +02:00
Add unit tests for InventoryMutateForm using jqwik
This adds the jqwik dependency for property based testing, like Haskell’s QuickCheck.
This commit is contained in:
parent
da19356496
commit
0c5e3f4e5c
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -60,3 +60,6 @@ hs_err_*.log
|
||||||
*.synctex.gz
|
*.synctex.gz
|
||||||
*.toc
|
*.toc
|
||||||
*.xdv
|
*.xdv
|
||||||
|
|
||||||
|
# jqwik
|
||||||
|
.jqwik-database
|
||||||
|
|
7
pom.xml
7
pom.xml
|
@ -58,6 +58,13 @@ SPDX-FileCopyrightText: 2023 swt23w23
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.jqwik</groupId>
|
||||||
|
<artifactId>jqwik</artifactId>
|
||||||
|
<version>1.8.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
|
|
|
@ -0,0 +1,266 @@
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
// SPDX-FileCopyrightText: 2024 swt23w23
|
||||||
|
package catering.inventory;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
import static org.salespointframework.core.Currencies.EURO;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.money.MonetaryAmount;
|
||||||
|
import javax.money.NumberValue;
|
||||||
|
|
||||||
|
import org.javamoney.moneta.Money;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.salespointframework.catalog.Product;
|
||||||
|
import org.salespointframework.inventory.UniqueInventoryItem;
|
||||||
|
import org.salespointframework.quantity.Metric;
|
||||||
|
import org.salespointframework.quantity.Quantity;
|
||||||
|
|
||||||
|
import catering.catalog.Consumable;
|
||||||
|
import catering.catalog.Rentable;
|
||||||
|
import catering.order.OrderType;
|
||||||
|
import net.jqwik.api.Arbitraries;
|
||||||
|
import net.jqwik.api.Arbitrary;
|
||||||
|
import net.jqwik.api.Assume;
|
||||||
|
import net.jqwik.api.Combinators;
|
||||||
|
import net.jqwik.api.ForAll;
|
||||||
|
import net.jqwik.api.Property;
|
||||||
|
import net.jqwik.api.Provide;
|
||||||
|
import net.jqwik.api.constraints.NotBlank;
|
||||||
|
|
||||||
|
public class InventoryMutateFormUnitTests {
|
||||||
|
/*
|
||||||
|
* Providers for jqwik
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Provide
|
||||||
|
Arbitrary<MonetaryAmount> euroMonetaryAmount() {
|
||||||
|
return Arbitraries.doubles()
|
||||||
|
.filter(amount -> amount >= 0)
|
||||||
|
.map(amount -> Money.of(amount, EURO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provide
|
||||||
|
Arbitrary<Optional<MonetaryAmount>> optionalEuroMonetaryAmount() {
|
||||||
|
return euroMonetaryAmount().optional();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provide
|
||||||
|
Arbitrary<Long> positiveOrZero() {
|
||||||
|
return Arbitraries.longs().filter(x -> x >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provide
|
||||||
|
Arbitrary<Consumable> consumable() {
|
||||||
|
return Combinators
|
||||||
|
.combine(Arbitraries.strings().filter(s -> !s.isBlank()), euroMonetaryAmount(), euroMonetaryAmount(),
|
||||||
|
optionalEuroMonetaryAmount(), Arbitraries.subsetOf(OrderType.values()),
|
||||||
|
Arbitraries.of(Metric.class))
|
||||||
|
.as((name, retailPrice, wholesalePrice, promotionPrice, orderTypes, metric) -> new Consumable(name,
|
||||||
|
retailPrice, wholesalePrice, promotionPrice, orderTypes, metric));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provide
|
||||||
|
Arbitrary<Rentable> rentable() {
|
||||||
|
return Combinators
|
||||||
|
.combine(Arbitraries.strings().filter(s -> !s.isBlank()), euroMonetaryAmount(), euroMonetaryAmount(),
|
||||||
|
Arbitraries.subsetOf(OrderType.values()),
|
||||||
|
Arbitraries.of(Metric.class))
|
||||||
|
.as((name, retailPrice, wholesalePrice, orderTypes, metric) -> new Rentable(name, retailPrice,
|
||||||
|
wholesalePrice, orderTypes, metric));
|
||||||
|
}
|
||||||
|
|
||||||
|
Arbitrary<UniqueInventoryItem> item(Arbitrary<? extends Product> product) {
|
||||||
|
return Combinators.combine(product, positiveOrZero())
|
||||||
|
.as((prod, qty) -> new UniqueInventoryItem(prod, prod.createQuantity(qty)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provide
|
||||||
|
Arbitrary<UniqueInventoryItem> consumableItem() {
|
||||||
|
return item(consumable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provide
|
||||||
|
Arbitrary<UniqueInventoryItem> rentableItem() {
|
||||||
|
return item(rentable());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Property-based tests with jqwik
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Property
|
||||||
|
void property_formToConsumableToFormIsIdentity(@ForAll @NotBlank String name,
|
||||||
|
@ForAll("positiveOrZero") long qty,
|
||||||
|
@ForAll Metric metric,
|
||||||
|
@ForAll("euroMonetaryAmount") MonetaryAmount retailPrice,
|
||||||
|
@ForAll("euroMonetaryAmount") MonetaryAmount wholesalePrice,
|
||||||
|
@ForAll("optionalEuroMonetaryAmount") Optional<MonetaryAmount> promotionPrice,
|
||||||
|
@ForAll Set<OrderType> orderTypes) {
|
||||||
|
ConsumableMutateForm form = new ConsumableMutateForm();
|
||||||
|
Assume.that(form.supportedMetrics().contains(metric));
|
||||||
|
form.setName(name);
|
||||||
|
form.setQuantity(qty);
|
||||||
|
form.setMetric(metric);
|
||||||
|
form.setRetailPrice(retailPrice.getNumber().doubleValueExact());
|
||||||
|
form.setWholesalePrice(retailPrice.getNumber().doubleValueExact());
|
||||||
|
form.setPromotionPrice(promotionPrice.map(MonetaryAmount::getNumber).map(NumberValue::doubleValueExact));
|
||||||
|
form.setOrderTypes(Set.of(OrderType.PARTY_SERVICE));
|
||||||
|
|
||||||
|
Product product = form.toProduct();
|
||||||
|
UniqueInventoryItem item = new UniqueInventoryItem(product, product.createQuantity(qty));
|
||||||
|
assertThat(ConsumableMutateForm.of(item))
|
||||||
|
.usingRecursiveComparison()
|
||||||
|
.isEqualTo(form);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Property
|
||||||
|
void property_formToRentableToFormIsIdentity(@ForAll @NotBlank String name,
|
||||||
|
@ForAll("positiveOrZero") long qty,
|
||||||
|
@ForAll Metric metric,
|
||||||
|
@ForAll("euroMonetaryAmount") MonetaryAmount retailPrice,
|
||||||
|
@ForAll("euroMonetaryAmount") MonetaryAmount wholesalePrice,
|
||||||
|
@ForAll Set<OrderType> orderTypes) {
|
||||||
|
RentableMutateForm form = new RentableMutateForm();
|
||||||
|
Assume.that(form.supportedMetrics().contains(metric));
|
||||||
|
form.setName(name);
|
||||||
|
form.setQuantity(qty);
|
||||||
|
form.setMetric(metric);
|
||||||
|
form.setRetailPrice(retailPrice.getNumber().doubleValueExact());
|
||||||
|
form.setWholesalePrice(retailPrice.getNumber().doubleValueExact());
|
||||||
|
form.setOrderTypes(Set.of(OrderType.PARTY_SERVICE));
|
||||||
|
|
||||||
|
Product product = form.toProduct();
|
||||||
|
UniqueInventoryItem item = new UniqueInventoryItem(product, product.createQuantity(qty));
|
||||||
|
assertThat(RentableMutateForm.of(item))
|
||||||
|
.usingRecursiveComparison()
|
||||||
|
.isEqualTo(form);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Property
|
||||||
|
void property_consumableToFormToConsumableIsIdentity(@ForAll("consumableItem") UniqueInventoryItem item) {
|
||||||
|
InventoryMutateForm form = InventoryMutateForm.of(item);
|
||||||
|
|
||||||
|
assertThat(form).isInstanceOf(ConsumableMutateForm.class);
|
||||||
|
assertThat(form.toProduct())
|
||||||
|
.usingRecursiveComparison()
|
||||||
|
.ignoringFields("id")
|
||||||
|
.isEqualTo(item.getProduct());
|
||||||
|
assertThat(form.getQuantity()).isEqualTo(item.getQuantity().getAmount().longValueExact());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Property
|
||||||
|
void property_rentableToFormToRentableIsIdentity(@ForAll("rentableItem") UniqueInventoryItem item) {
|
||||||
|
InventoryMutateForm form = InventoryMutateForm.of(item);
|
||||||
|
|
||||||
|
assertThat(form).isInstanceOf(RentableMutateForm.class);
|
||||||
|
assertThat(form.toProduct())
|
||||||
|
.usingRecursiveComparison()
|
||||||
|
.ignoringFields("id")
|
||||||
|
.isEqualTo(item.getProduct());
|
||||||
|
assertThat(form.getQuantity()).isEqualTo(item.getQuantity().getAmount().longValueExact());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Property
|
||||||
|
void property_consumableFormModifiesExistingConsumable(@ForAll("consumableItem") UniqueInventoryItem item,
|
||||||
|
@ForAll("consumable") Consumable product) {
|
||||||
|
InventoryMutateForm.of(item).modifyProduct(product);
|
||||||
|
|
||||||
|
assertThat(product)
|
||||||
|
.usingRecursiveComparison()
|
||||||
|
.ignoringFields("id")
|
||||||
|
.ignoringFields("metric") // metric can’t be modified (salespoint limitation)
|
||||||
|
.isEqualTo(item.getProduct());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Property
|
||||||
|
void property_rentableFormModifiesExistingConsumable(@ForAll("rentableItem") UniqueInventoryItem item,
|
||||||
|
@ForAll("rentable") Rentable product) {
|
||||||
|
InventoryMutateForm.of(item).modifyProduct(product);
|
||||||
|
|
||||||
|
assertThat(product)
|
||||||
|
.usingRecursiveComparison()
|
||||||
|
.ignoringFields("id")
|
||||||
|
.ignoringFields("metric") // metric can’t be modified (salespoint limitation)
|
||||||
|
.isEqualTo(item.getProduct());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Edge cases with jqwik
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Property
|
||||||
|
void property_ofIllegal(@ForAll("consumableItem") UniqueInventoryItem consumableItem,
|
||||||
|
@ForAll("rentableItem") UniqueInventoryItem rentableItem) {
|
||||||
|
assertThatThrownBy(() -> InventoryMutateForm
|
||||||
|
.of(new UniqueInventoryItem(new Product("no subclass", Money.of(0.0, EURO)), Quantity.of(1))))
|
||||||
|
.isInstanceOf(IllegalArgumentException.class);
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> ConsumableMutateForm.of(rentableItem))
|
||||||
|
.isInstanceOf(IllegalArgumentException.class);
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> RentableMutateForm.of(consumableItem))
|
||||||
|
.isInstanceOf(IllegalArgumentException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Property
|
||||||
|
void property_modifyIllegalProduct(@ForAll("consumableItem") UniqueInventoryItem consumableItem,
|
||||||
|
@ForAll("rentableItem") UniqueInventoryItem rentableItem,
|
||||||
|
@ForAll("consumable") Consumable consumable,
|
||||||
|
@ForAll("rentable") Rentable rentable) {
|
||||||
|
assertThatThrownBy(() -> InventoryMutateForm.of(rentableItem).modifyProduct(consumable))
|
||||||
|
.isInstanceOf(IllegalArgumentException.class);
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> InventoryMutateForm.of(consumableItem).modifyProduct(rentable))
|
||||||
|
.isInstanceOf(IllegalArgumentException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* JUnit Unit tests
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void toConsumable() {
|
||||||
|
ConsumableMutateForm form = new ConsumableMutateForm();
|
||||||
|
form.setName("Weißwurst (vegan)");
|
||||||
|
form.setQuantity(10L);
|
||||||
|
form.setMetric(Metric.UNIT);
|
||||||
|
form.setRetailPrice(3.46);
|
||||||
|
form.setWholesalePrice(1.50);
|
||||||
|
form.setPromotionPrice(Optional.of(3.33));
|
||||||
|
form.setOrderTypes(Set.of(OrderType.PARTY_SERVICE));
|
||||||
|
assertThat(form.getQuantity()).isEqualTo(10L);
|
||||||
|
assertThat(form.toProduct())
|
||||||
|
.usingRecursiveComparison()
|
||||||
|
.ignoringFields("id")
|
||||||
|
.isEqualTo(new Consumable("Weißwurst (vegan)", Money.of(3.46, EURO), Money.of(1.50, EURO),
|
||||||
|
Optional.of(Money.of(3.33, EURO)), Set.of(OrderType.PARTY_SERVICE), Metric.UNIT));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void toRentable() {
|
||||||
|
RentableMutateForm form = new RentableMutateForm();
|
||||||
|
form.setName("Kebab-Drehspieß „Der Gerät“ Alkadur");
|
||||||
|
form.setQuantity(3L);
|
||||||
|
form.setMetric(Metric.UNIT);
|
||||||
|
form.setRetailPrice(20.0);
|
||||||
|
form.setWholesalePrice(10000.0);
|
||||||
|
form.setOrderTypes(Set.of(OrderType.EVENT_CATERING));
|
||||||
|
assertThat(form.getQuantity()).isEqualTo(3L);
|
||||||
|
assertThat(form.toProduct())
|
||||||
|
.usingRecursiveComparison()
|
||||||
|
.ignoringFields("id")
|
||||||
|
.isEqualTo(new Rentable("Kebab-Drehspieß „Der Gerät“ Alkadur", Money.of(20.0, EURO),
|
||||||
|
Money.of(10000.0, EURO), Set.of(OrderType.EVENT_CATERING), Metric.UNIT));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void forProductType() {
|
||||||
|
assertThat(InventoryMutateForm.forProductType(Consumable.class)).isInstanceOf(ConsumableMutateForm.class);
|
||||||
|
assertThat(InventoryMutateForm.forProductType(Rentable.class)).isInstanceOf(RentableMutateForm.class);
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> InventoryMutateForm.forProductType(Product.class)).isInstanceOf(IllegalArgumentException.class);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue