Test Driven Development Example: Creating a Loan App
In my last article, I debunked some misconceptions around Test Driven Development (TDD), and explained some of the benefits of this framework when compared to other approaches. Now, I’m going to show you the power of TDD with an example: let’s create a Loan App.
The Exercise: Creating a Loan App with TDD
In this exercise, I’ll demonstrate how to apply TDD while developing on the OutSystems platform.
Our product owner came up with some requirements for our loan app:

He was also kind enough to provide me with a helpful spreadsheet and a formula so I can understand all the calculations involved:

Meanwhile, the project manager...

Scenario 1: Payment Calculation
We’ll be developing using TDD as a framework, where:
- Red - Write a failing test
- Green - Make the test pass
- Blue - Refactor
So let's create an app for the tests, the loan app, and a library for the calculations.
The Loan App Test is a reactive web app and has a single testing module that references the TDD Framework (or the official BDD Framework).

The Loan App is also a web reactive app and includes a library for the financial calculations.

Red - Create a Failing Test
We need to calculate the payment amount based on the initial principal, number of payments, and interest rate.
Since this is test-driven, on the test side, we create the initial test.

On the library side, we create a method with a dummy implementation for now.
Back to the test side, we implement the test.

And we have our first failing scenario.

Now we can start to code… or can’t we?
We actually already did, driven by the tests. What have we learned so far?
- We decided where to put the payment method and in what type of module.
- The payment method needs 3 inputs (Principal, Interest rate, and # of Payments).
- The payment method has a single output (Payment Amount).
- The payment method has no dependencies and can live isolated in its own library (yes, I cut some corners here).
- We learned the domain language, principal, interest rate, number of payments, and payment now all have very specific meanings.
Green - Make the Test Pass
So, now we can flip a switch on our brain and take care of the implementation.
This is a simple mathematical formula. I know how to implement it, so I can just go for the solution.
In some cases, the solution is not clear. If so, we can benefit from coding in microsteps (see Uncle Bob example below) and the solution shows itself on the refactor step.
And it fails again, with a rounding issue. Rounding in financial applications is a problem and should be done as late as possible and on a single time so it doesn’t accumulate rounding errors. So, we’ll fix the test.
And now we have a passing test.

Blue - Optimize Your Code
Well, there isn’t much to optimize when you just have a simple formula.
I did create this method as a client-side (Javascript) code. I’m thinking that complex power math operations on a client-side and this won’t be usable by any server-side applications, including traditional web.
Let’s convert this to a service really quickly and do the validations.
On the Financial Utils, copy the client method and paste it on the server-side.
On the tests, replace the client method by the server-side method.
And with a refactor, we still have a passing test.

Red - Create a Failing Test
We start by coding three more tests.

And naturally, these will fail.
On the Financial Utils add the validations.

And now all tests pass.
Scenario 2: Payment Schedule
We also need to be able to show the user a payment schedule.

Again, we have an example worksheet:

Let's get started.
Red - Create a Failing Test

We need another method for this, something that returns the payment schedule. I'm choosing to have the same inputs as the payment method, and output a list with the payment schedule.
We'll assert for principal amount of payment #10 and the balance for the last payment, which should be zero.

And it fails miserably.

Green - Make the Test Pass
Time to flip that switch again on our brain and implement the calculations.

And the test passes.
You can take as many iterations of this step as needed. You don't think I got it right on the very first pass, do you?

Blue - Optimize Your Code
At this moment I can't think of any code optimizations.
Scenario 3: Extra Payments
Often, the user inquires what the payment schedule looks like if they pay something extra.

Again, we have an example worksheet:
By now, you know the drill.
Red - Create a Failing Test
Whoa, wait a second, just thinking about the methods and the interface, I have many options.
- Option 1: Create a new method which takes an existing schedule and processes the extra payments.
- Option 2: Modify the existing method to support the new feature.
Also, should I choose an array of extra payments or force the developer to execute the method as many times as there are extra payments?
Sometimes, as a developer, you’re faced with these types of decisions. There are pros and cons to both of them. So, let's choose option 1 and take microsteps to see where it leads us.
And the test fails.

Green - Make the Test Pass
The simple, straightforward way looks something like this:
And the test passes.

Blue - Optimize Your Code
Well, this code is almost the same as the Payment Schedule. It needs the interest rate and is re-calculating the payment on every payment turn. Option 2 was a better choice.
Let's refactor this and see if we break all the test cases!
Replace the payment extra method from the last test:

All tests are passing (view from the dashboard).
Of course, a lot more tests are needed, but this is it for this example.
Conclusion
TDD is awesome! I’m getting addicted to this rhythm of Red/Green/Blue which on my mind is more like:
- Method and interfaces
- Code implementation
- Refactor/Optimize
Did I write more code when compared to a more traditional “Bug Driven Development”? Yes, for sure. However, being a developer I don’t really mind, after all, it’s what I do.
Think of all the time and effort I saved by not having to do all these tests manually and repeatedly every time I changed something just to check if it was working.
Give TDD and try and check out the components and this example on the Forge:

And if you want to know more about TDD, these will get you started:
- Dave Farley
- Sandro Mancuso
- Robert Martin (Uncle Bob)
- Chew Choon Keat (Bug Driven Development)
- Ian Cooper
This post was inspired by Kent Beck’s book “TDD by Example”.