2026-06-21 18:31:29 +02:00
2026-06-17 13:21:30 +02:00
2026-06-17 13:21:30 +02:00
2026-06-17 13:21:30 +02:00
2026-06-21 18:31:29 +02:00

Pet Insurance — Code Challenge

A Java coding challenge implementing a data driven calculation logic for a highly extensible pet health insurance product.

Build & test

Requires Java 25 and Maven 3.x.

# Compile
mvn compile

# Run all tests
mvn test

# Full build
mvn package

Project structure

src/
├── main/
│   ├── java/com/pfefferminzia/petinsurance/
│   │   ├── animals/          # Animal sealed interface + Dog, Cat, SmallAnimal records
│   │   ├── calculations/     # InsuranceContract, Calculations, CalculationResult
│   │   ├── exception/        # InvalidInsuranceContractException
│   │   └── tariffs/          # TariffOption, TariffConfiguration, TariffLoader
│   └── resources/
│       └── tariff.properties # Runtime tariff configuration
└── test/
    ├── java/.../calculations/
    │   └── CalculationsTest.java
    └── resources/
        └── tariff.properties # Test tariff configuration (mirrors main)

Architecture

Animals

Animal is a sealed interface (permits Dog, Cat, SmallAnimal). Each type is an immutable record:

  • Dog(LocalDate birthday, String breed) — identifies with species key "DOG"
  • Cat(LocalDate birthday) — species key "CAT"
  • SmallAnimal(LocalDate birthday) — species key "SMALLANIMAL"

The interface exposes birthday() and speciesKey(). Base insurance sums are not hardcoded in the animal types; they live in configuration (see below).

Tariff configuration (tariff.properties)

All tariff data is loaded from tariff.properties at startup via TariffLoader.loadFromFile(), which produces a TariffConfiguration record. This makes adding new tariffs, animals, age brackets, or breed adjustments a config-only change.

# Animal base insurance sums
baseSum.DOG=2500.00
baseSum.CAT=2000.00
baseSum.SMALLANIMAL=1000.00

# Tariffs: factor,availableFromDate
tariffs.KOMPAKT=1.0,1970-01-01
tariffs.OPTIMAL=1.2,1970-01-01
tariffs.PREMIUM=1.4,2026-07-01

# Age-based premium factors (≤ age → factor; elderlyFactor covers > 7)
age.2=0.20
age.5=0.25
age.7=0.28
elderlyFactor=0.30

# Dog breed surcharge (positive) / discount (negative)
breed.DACKEL=-0.1
breed.BERNHARDINER=0.1

TariffConfiguration.getTariffFactor(tariffName, startDate) throws IllegalStateException if the chosen tariff is not yet available on the given start date (e.g. PREMIUM before 2026-07-01).

Calculation flow

  1. Build an InsuranceContract(animal, insuranceStartDate, tariffName). The record constructor validates all fields eagerly and throws InvalidInsuranceContractException collecting all violations.
  2. Call Calculations.calculateInsuranceSumAndYearlyPremium(contract), which returns a CalculationResult(insuranceSum, yearlyPremium).

Insurance sum = baseSum(animal) × tariffFactor

Yearly premium = insuranceSum × ageFactor × (1 + breedFactor)

  • ageFactor is looked up from the age bracket table based on exact years between birthday and insuranceStartDate.
  • breedFactor only applies to Dog; all other animals use 0 (no adjustment).

Worked examples

Animal Insurance sum Yearly premium
Husky, 7y, PREMIUM 3500 980
Dackel, 7y, PREMIUM 3500 882
Bernhardiner, 7y, PREMIUM 3500 1078
Cat, 3y, OPTIMAL 2400 600
SmallAnimal, 1y, KOMPAKT 1000 200

All five examples are covered by CalculationsTest.

Extensibility

  • New animal type — add a record implementing Animal, register its base sum in tariff.properties.
  • New tariff — add one line to tariff.properties with a factor and availability date.
  • New breed adjustment — add one line to the breed.* section.
  • New age bracket — add one age.N entry; TariffConfiguration.getAgeFactor uses a NavigableMap ceiling lookup so ordering is automatic.
  • New calculation — extend Calculations or add a new method; CalculationResult can be widened to carry additional fields.
S
Description
A Java coding challenge implementing a data driven calculation logic for an extensible pet health insurance product.
Readme
62 KiB
Languages
Java 100%