The Beverages Prices Refactoring kata: a kata to practice refactoring away from an awful application of inheritance.
Published by Manuel Rivero on 07/04/2019
I created the Beverages Prices Refactoring kata for the Deliberate Practice Program I’m running at Lifull Connect offices in Barcelona (previously Trovit). Its goal is to practice refactoring away from a bad usage of inheritance.
The code computes the price of the different beverages that are sold in a coffee house. There are some supplements that can be added to those beverages. Each supplement increases the price a bit. Not all combinations of drinks and supplements are possible.
Just having a quick look at the tests of the initial code would give you an idea of the kind of problems it might have:
| package unit_tests; | |
| import beverages.*; | |
| import org.junit.Test; | |
| import static org.hamcrest.CoreMatchers.is; | |
| import static org.hamcrest.MatcherAssert.assertThat; | |
| import static org.hamcrest.Matchers.closeTo; | |
| public class BeveragesPricingTest { | |
| private static final double PRECISION = 0.001; | |
| @Test | |
| public void computes_coffee_price() { | |
| Beverage coffee = new Coffee(); | |
| assertThat(coffee.price(), is(closeTo(1.20, PRECISION))); | |
| } | |
| @Test | |
| public void computes_tea_price() { | |
| Beverage tea = new Tea(); | |
| assertThat(tea.price(), is(closeTo(1.50, PRECISION))); | |
| } | |
| @Test | |
| public void computes_hot_chocolate_price() { | |
| Beverage hotChocolate = new HotChocolate(); | |
| assertThat(hotChocolate.price(), is(closeTo(1.45, PRECISION))); | |
| } | |
| @Test | |
| public void computes_tea_with_milk_price() { | |
| Tea teaWithMilk = new TeaWithMilk(); | |
| assertThat(teaWithMilk.price(), is(closeTo(1.60, PRECISION))); | |
| } | |
| @Test | |
| public void computes_coffee_with_milk_price() { | |
| Coffee coffeeWithMilk = new CoffeeWithMilk(); | |
| assertThat(coffeeWithMilk.price(), is(closeTo(1.30, PRECISION))); | |
| } | |
| @Test | |
| public void computes_coffee_with_milk_and_cream_price() { | |
| Coffee coffeeWithMilkAndCream = new CoffeeWithMilkAndCream(); | |
| assertThat(coffeeWithMilkAndCream.price(), is(closeTo(1.45, PRECISION))); | |
| } | |
| @Test | |
| public void computes_hot_chocolate_with_cream_price() { | |
| HotChocolateWithCream hotChocolateWithCream = new HotChocolateWithCream(); | |
| assertThat(hotChocolateWithCream.price(), is(closeTo(1.60, PRECISION))); | |
| } | |
| } |
If that’s not enough have a look at its inheritance hierarchy:

To make things worse, we are asked to add an optional cinnamon supplement that costs 0.05€ to all our existing catalog of beverages. We think we should refactor this code a bit before introducing the new feature.
We hope you have fun practicing refactoring with this kata.
Originally published in Manuel Rivero's blog.