CHAPTER 4
Test-driven development is a software development technique in which the requirements are written as test cases, and the software is written/refactored to pass the various test cases.
An automated teller machine (ATM) is being created, and we are designing the software for it. We plan on a method called ShouldCashBeDisbursed() and expect a Boolean value to be returned. Code Listing 6 shows our initial code.
Code Listing 6: ShouldCashBeDisbursed function
public ShouldCashBeDisbursed(balance: number , withdrawal: number ) { let ans = null; return ans; } |
At this point, our code does nothing except return a NULL. If you had created an interface, this code might be the default implementation for one of the definitions.
We start by writing our test cases, which we’d expect to all fail. Listing 7 shows our test cases.
Code Listing 7: Test cases
it('should dispense $200 when balance = $1000', () => { let ans = component.ShouldCashBeDisbursed(1000,200); expect(ans).toEqual(true); }); it('should not dispense $200 when balance = $150', () => { let ans = component.ShouldCashBeDisbursed(150,200); expect(ans).toEqual(false); }); |
We now write the code necessary to pass these tests. However, as you write the tests, you will likely think of additional tests you might want to add. What happens if the requested withdrawal amount is 0? Or a negative number? Thinking through your test steps can help you write a more robust method.
Once you’ve written your tests, you can go ahead and code the method. In addition to helping you think of your design, you’ve also built a regression test plan to ensure future changes to the method do not break previous features. Code Listing 8 shows our final test steps.
Code Listing 8: Withdrawal test cases
it('should dispense $200 when balance = $1000', () => { let ans = component.ShouldCashBeDisbursed(1000,200); expect(ans).toEqual(true); }); it('should not dispense $200 when balance = $150', () => { let ans = component.ShouldCashBeDisbursed(150,200); expect(ans).toEqual(false); }); it('should not dispense when withdrawal is negative', () => { let ans = component.ShouldCashBeDisbursed(1000,-200); expect(ans).toEqual(false); }); it('should not dispense when withdrawal is 0', () => { let ans = component.ShouldCashBeDisbursed(150,0); expect(ans).toEqual(false); }); |
Code Listing 9 shows our method.
Code Listing 9: AllowWithdrawal method
public ShouldCashBeDisbursed(balance: number , withdrawal: number ) { const shouldAllow = (balance - withdrawal > 0) && (withdrawal>0) if (shouldAllow) { balance = balance - withdrawal; } return (shouldAllow); } |
When we run this in the test runner (described in later chapters), the result is our expected passed tests. Figure 7 shows the test runner results.

Figure 7: Test results
While test-driven development works, it is generally focused at the method level. This is fine for developers, but not necessarily for business analysts. They are more concerned with the behavior of the system, not the details of the methods. This is the focus of behavior-driven development (BDD). The business analysts write the expected behavior, which acts as a specification and a test plan for the development team.
Let’s look at how business analysts might expect the ATM withdrawal function to work. The business analyst will think in terms of the user and create user stories. The user story for the ATM might look like:
Using the Gherkin language, the business analyst will then write examples of how they expect the system to behave. For example,
And:
So far, this is good, but now they add a couple more scenarios:
And:
Now that the business analysts have written their expected behavior out, the developer realizes that a Boolean return value won’t work. The method needs to return a status code, since the error message needs to be different. Also notice that the business analyst never considered the negative amount case, since most ATM machines don’t have + or – buttons.
When the tests are written first, it forces more thinking and designing, instead of jumping in and coding right away. Whether the tests are written by developers or business analysts, the design work of writing the test plan first has several benefits:
There are many available tools for and variations of test-driven development. In the next few chapters, we will explore the Angular environment for working with this approach.