Calculator Refactor

Level: Advanced 60–90 min

Concepts: Refactoring

Solutions: C# | TypeScript | Python


You are given a calculator application. However, the solution is not perfect. All logic sits in “action scripts” behind button clicks, there are no test and it does not always handle operations correctly. E.g 1++2 equals 3 instead of “Error”

The code for this kata can be found at https://github.com/TDDBuddy/Wpf-Calculator-Kata

Your job is to write tests for the code, refactoring the code to create testable units pulling code left behind button clicks into something structured.

  • Keep your check-ins small by limiting each one to a single refactoring.
  • Should you find any bugs, fix them as you go by creating a failing test and then making it pass; then return to refactoring.

Bonus

Try and avoid the use of if or switch statements in your final solution.

Reference Walkthrough

Reference implementations in C#, TypeScript, and Python live at tddbuddy-reference-katas/calc-refactor. This is an F2 refactoring kata: the legacy WPF calculator’s behavior is captured in a shared characterization set (SCENARIOS.md), and each language ships a clean Calculator domain object that satisfies that contract byte-for-byte — including the fixed behavior for the 1++2 = 3 bug the brief calls out (the reference displays "Error", not 3) and division by zero (also "Error").

Scope note — calculator core only. The reference is scoped to the pure calculator domain: press(key) in, display string out. The WPF UI, event handlers, decimal entry, floating-point arithmetic, and memory buttons are all out of scope — a deliberate tightening that keeps the characterization set decidable and the F2 surface small. A small test-folder CalculatorBuilder lets every scenario open with one line naming the key sequence it exercises: aCalculator().pressKeys("1+2=").build().

This kata ships in Agent Full-Bake mode at middle gear, the F2 (light builder) tier. See the repo’s Gears section for why middle gear is the deliberate choice once the characterization set is settled — the refactor lands in one commit per language because the bugs-vs-intent decisions were made up front, in SCENARIOS.md.