PricingService.java

1
package com.rbctcsworld.ecommerce.pricing;
2
3
import org.springframework.beans.factory.annotation.Value;
4
import org.springframework.stereotype.Service;
5
6
import java.math.BigDecimal;
7
import java.math.RoundingMode;
8
9
/**
10
 * Pure calculation, no database: easy to unit-test every boundary.
11
 *
12
 *   merchandise = subtotal - discount
13
 *   shipping    = 0 if merchandise >= freeShippingThreshold, else shippingFee
14
 *   tax         = merchandise * taxRate   (shipping is not taxed)
15
 *   total       = merchandise + shipping + tax
16
 * All money is rounded HALF_UP to 2 decimals.
17
 */
18
@Service
19
public class PricingService {
20
21
    private final BigDecimal taxRate;
22
    private final BigDecimal freeShippingThreshold;
23
    private final BigDecimal shippingFee;
24
25
    public PricingService(@Value("${app.pricing.tax-rate}") BigDecimal taxRate,
26
                          @Value("${app.pricing.free-shipping-threshold}") BigDecimal freeShippingThreshold,
27
                          @Value("${app.pricing.shipping-fee}") BigDecimal shippingFee) {
28
        this.taxRate = taxRate;
29
        this.freeShippingThreshold = freeShippingThreshold;
30
        this.shippingFee = shippingFee;
31
    }
32
33
    public PriceBreakdown price(BigDecimal subtotal, BigDecimal discount) {
34
        BigDecimal sub = money(subtotal);
35
        BigDecimal disc = money(discount.min(sub)); // a discount can never exceed the subtotal
36
        BigDecimal merchandise = sub.subtract(disc);
37 2 1. price : changed conditional boundary → KILLED
2. price : removed conditional - replaced comparison check with false → KILLED
        BigDecimal shipping = merchandise.compareTo(freeShippingThreshold) >= 0 ? money(BigDecimal.ZERO) : money(shippingFee);
38
        BigDecimal tax = money(merchandise.multiply(taxRate));
39
        BigDecimal total = merchandise.add(shipping).add(tax);
40 1 1. price : replaced return value with null for com/rbctcsworld/ecommerce/pricing/PricingService::price → KILLED
        return new PriceBreakdown(sub, disc, shipping, tax, money(total));
41
    }
42
43
    public static BigDecimal money(BigDecimal v) {
44 1 1. money : replaced return value with null for com/rbctcsworld/ecommerce/pricing/PricingService::money → KILLED
        return v.setScale(2, RoundingMode.HALF_UP);
45
    }
46
47
    public record PriceBreakdown(BigDecimal subtotal, BigDecimal discount, BigDecimal shippingFee,
48
                                 BigDecimal tax, BigDecimal total) {
49
    }
50
}

Mutations

37

1.1
Location : price
Killed by : com.rbctcsworld.ecommerce.pricing.PricingServiceTest.[engine:junit-jupiter]/[class:com.rbctcsworld.ecommerce.pricing.PricingServiceTest]/[test-template:breakdown(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)]/[test-template-invocation:#4]
changed conditional boundary → KILLED

2.2
Location : price
Killed by : com.rbctcsworld.ecommerce.pricing.PricingServiceTest.[engine:junit-jupiter]/[class:com.rbctcsworld.ecommerce.pricing.PricingServiceTest]/[test-template:breakdown(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)]/[test-template-invocation:#4]
removed conditional - replaced comparison check with false → KILLED

40

1.1
Location : price
Killed by : com.rbctcsworld.ecommerce.pricing.PricingServiceTest.[engine:junit-jupiter]/[class:com.rbctcsworld.ecommerce.pricing.PricingServiceTest]/[test-template:breakdown(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)]/[test-template-invocation:#4]
replaced return value with null for com/rbctcsworld/ecommerce/pricing/PricingService::price → KILLED

44

1.1
Location : money
Killed by : com.rbctcsworld.ecommerce.pricing.PricingServiceTest.[engine:junit-jupiter]/[class:com.rbctcsworld.ecommerce.pricing.PricingServiceTest]/[test-template:breakdown(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)]/[test-template-invocation:#4]
replaced return value with null for com/rbctcsworld/ecommerce/pricing/PricingService::money → KILLED

Active mutators

Tests examined


Report generated by PIT 1.30.0 support