 • Search in book...
• Toggle Font Controls

# Chapter 1. The Money Problem

I would not give a fig for the simplicity this side of complexity, but I would give my life for the simplicity on the other side of complexity.

Oliver Wendell Holmes Jr.

Our development environment are ready. In this chapter, we’ll learn the three phases that support test-driven development. We’ll then write our first code feature using test-driven development.

# Red-Green-Refactor — The Building Blocks of TDD

Test-driven development follows a three-phase process. The three phases are:

1. RED. We write a failing test (including possibly compilation failures). We run the test suite to verify the failing tests.

2. GREEN. We write just enough production code to make the test green. We run the test suite the verify this.

3. REFACTOR. We remove any code-smells. These may be due to duplication, hard-coded values, or improper use of language idioms (e.g. using a verbose loop instead of a built-in iterator). If we break any tests during refactoring, we prioritize getting them back to green before exiting this phase.

This is the RED-GREEN-REFACTOR cycle (aka RGR), shown in Figure 1-1. The three phases of this cycle are the essential building blocks of test-driven development. All the code we’ll develop in this book will follow this cycle.

###### Important

The three phases of the RED-GREEN-REFACTOR cycle are the essential building blocks of TDD.

# What’s the problem?

We have a money problem. No, not the kind that almost everyone has: not having enough of it! It’s more of a “we want to keep track of our money” problem.

Say we have to build a spreadsheet to manage money in more than one currency. This could be to manage a stock portfolio.

Stock Stock Exchange Shares Share Price Total

IBM

NASDAQ

100

124 USD

12400 USD

BMW

DAX

400

75 EUR

30000 EUR

Samsung

KSE

300

68000 KRW

20400000 KRW

To build this spreadsheet, we’d need to do simple arithmetic operations on numbers in any one currency:

 5 USD x 2 = 10 USD 10 EUR x 2 = 20 EUR 4002 KRW / 4 = 1001.5 KRW

We’d also like to convert between currencies. For example, if exchanging 1 EUR get us 1.2 USD, and exchanging 1 USD gets us 1100 KRW:

 5 USD + 10 EUR = 17 USD 1 USD + 1100 KRW = 2200 KRW

Each of the aforementioned line items will be one (teeny tiny) feature that we’ll implement using TDD. We already have several features to implement. In order to help us focus on one thing at a time, we’ll highlight the feature we’re working on in bold. When we’re done with a feature, we’ll signal our satisfaction by crossing it out.

So where should we start? If the title of this book isn’t an obvious give-away: we’ll start by writing a test.

# Our first failing test

Let’s start by implementing the very first feature in our list:

 5 USD x 2 = 10 USD 10 EUR x 2 = 20 EUR 4002 KRW / 4 = 1000.5 KRW 5 USD + 10 EUR = 17 USD 1 USD + 1100 KRW = 2200 KRW

## Go

In a new file called `money_test.go` in the `go` folder, let’s write our first test:

````package`` ``main`` ` ```

````import`` ``(````
````    ``"testing"`` ` ```
````)````
``````
````func`` ``TestMultiplication``(``t`` ``*``testing``.``T``)`` ``{`` ` ```
````fiver`` ``:=`` ``Dollar``{`` ` ```
````amount``:`` ``5``,````
````    ``}````
````    ``tenner`` ``:=`` ``fiver``.``Times``(``2``)`` ` ```
````if`` ``tenner``.``amount`` ``!=`` ``10`` ``{`` ` ```
````t``.``Errorf``(``"Expected 10, got: [%d]"``,`` ``tenner``.``amount``)`` ` ```
````}````
````}```` Package declaration Imported “testing” package, used in `t.Errorf` later Our test method, must start with `Test` and have one `*testing.T` argument Struct representing “USD 5”. `Dollar` does not exist yet Method under test: `Times` — which also does not exist yet Comparing actual value with expected value Ensuring test fails if expected value is not equal to actual value

This test function includes a bit of boilerplate code.

The `package main` declares that all ensuing code is part of the `main` package. This is a requirement for standalone executable Go programs. Package management is a sophisticated feature in Go. It’s discussed in more detail in Chapter 5.

Next, we import the `testing` packages using the `import` statement. This package will be used in the unit test.

The unit test `func` tion is the bulk of the code. We declare an entity representing “5 USD”. This is the variable named `fiver`, which we initialize to a struct holding 5 in its `amount` field. Then, we multiply this `fiver` by 2. And we we expect the result to be 10 dollars, i.e. a variable `tenner` whose `amount` field must equal 10. If this isn’t the case, we print a nicely formatted error message with the actual value (whatever that may be).

When we run this test using "`go test -v .`" from the TDD Project Root folder, we should get an error:

````...` `undefined``:` `Dollar`
`FAIL`	`tdd` `[``build` `failed``]`
`FAIL````

We get the message loud and clear: that’s our first failing test!

###### Tip

"`go test -v .`" runs the tests in the current folder; and "`go test -v ./...`" 1 runs tests in the current folder and any sub-folders. The `-v` switch produces verbose output.

## JavaScript

In a new file called `test_money.js` in the `js` folder, let’s write our first test:

````const`` ``assert`` ``=`` ``require``(``'assert'``)``;`` ` ```

````fiver`` ``=`` ``new`` ``Dollar``(``5``)``;`` ` ```
````tenner`` ``=`` ``fiver``.``times``(``2``)``;`` ` ```
````assert``.``strictEqual``(``tenner``.``amount``,`` ``10``)``;`` ` ``` Importing the `assert` package, needed for the assertion later Object representing “USD 5”. `Dollar` does not exist yet Method under test: `times` — which also does not exist yet Comparing actual value with expected value in a `strictEqual` assert statement

JavaScript has minimal boilerplate code — the only line in addition to the test code is the `require` statement. This gives us access to the `assert` NPM package.

After that line are the three lines of code that form our test. We create an object representing 5 USD, we multiply it by 2, and we expect the result to be 10.

When we run this code from the TDD Project Root folder using `node js/test_money.js`, we should get an error that starts like this:

``ReferenceError``:` `Dollar` `is` `not` `defined``

That’s our first failing test. Hooray!

###### Tip

`node file.js` runs the JavaScript code in `file.js` and produces output. We use this command to run our tests.

## Python

In a new file called `test_money.py` in the `py` folder, let’s write our first test:

````import`` ``unittest`` ` ```
``````
````class`` ``TestMoney``(``unittest``.``TestCase``)``:`` ` ```
````  ``def`` ``testMultiplication``(``self``)``:`` ` ```
````    ``fiver`` ``=`` ``Dollar``(``5``)`` ` ```
````    ``tenner`` ``=`` ``fiver``.``times``(``2``)`` ` ```
````    ``self``.``assertEqual``(``10``,`` ``tenner``.``amount``)`` ` ```
``````
````if`` ``__name__`` ``==`` ``'``__main__``'``:`` ` ```
````    ``unittest``.``main``(``)```` Importing the `unittest` package, needed for the `TestCase` superclass Our test class, which must subclass the `unittest.TestCase` class Our method name must start with `test` to qualify as a test method Object representing “USD 5”. `Dollar` does not exist yet Method under test: `times` — which also does not exist yet Comparing actual value with expected value in a `assertEqual` statement The `main` idiom, ensures this class can be run as a script

Python requires `import` ing the `unittest` package, creating a class that subclasses `TestCase`, and `def` ining a function whose name starts with `test`. To be able to run the class as a standalone program, we need the common Python idiom that runs the `unittest.main()` function when `test_money.py` is run directly.

The test function describes how we expect our code to work. We define a variable named `fiver` and initialize it to a desired (but yet-to-be-created) class `Dollar` with `5` as a constructor argument. We then multiply `fiver` by `2` and store the result in a variable `tenner`. Finally, we expect the `amount` in `tenner` to be `10`.

When we run this code from the TDD Project Root folder using `python3 py/test_money.py -v`, we get an error:

``NameError``:` `name` `'Dollar'` `is` `not` `defined``

That’s our first failing test. Hooray!

###### Tip

`python3 file.py -v` runs the python code in `file.py` and produces verbose output. We use this command to run our tests.

# Going for green

We wrote our tests as we would expect them to work, blithely ignoring all syntax errors for the moment. Is this smart?

In the very beginning — which is where we are — it is smart to start with the smallest bit of code that sets us on the path to progress. Of course our tests fail because we haven’t defined what `Dollar` is. This may seem the perfect time to say “duh!” However, a wee bit of patience is warranted for these two reasons:

1. We have just finished the first step — getting to RED — of our first test. Not only is this the beginning, it’s the very beginning of the beginning.

2. We can (and will) speed up the increments as we go along. However, it’s important to know that we can slow down when we need to.

The next step is to get to GREEN.

It’s clear we need to introduce an abstraction `Dollar`. This section defines how to introduce this and other abstraction to get our test to pass.

## Go

Add an empty `Dollar struct` to the end of `money_test.go`.

````type` `Dollar` `struct` `{`
`}````

When we run the test now, we get a new error:

``...` `unknown` `field` `'``amount``'` `in` `struct` `literal` `of` `type` `Dollar``

Progress!

The error message is directing us to introduce a field named `amount` in our `Dollar` struct. So let’s do this, using an `int` data type for now (which is sufficient for our goal):

````type` `Dollar` `struct` `{`
`amount` `int`
`}````

Adding the `Dollar struct`, rather predictably, gets us to the next error:

``...` `fiver``.``Times` `undefined` `(``type` `Dollar` `has` `no` `field` `or` `method` `Times``)``

We see a pattern here: when there is something (a field or method) that’s undefined, we get this `undefined` error from the Go runtime. We will use this information to speed up our TDD cycles in the future. For now, let’s add a `func`tion named `Times`. We know, from how we wrote our test, that this function needs to take a number (the multiplier) and return another number (the result).

But how should we calculate the result? We know basic arithmetic how to multiply two numbers. But if we were to write the simplest code that works, we’d be justified in always returning the result that our test expects, that is, a struct representing 10 dollars:

````func` `(``d` `Dollar``)` `Times``(``multiplier` `int``)` `Dollar` `{`
`return` `Dollar``{``10``}`
`}````

When we run our code now, we should get a short and sweet response on our terminal:

````==``=` `RUN`   `TestMultiplication`
`---` `PASS``:` `TestMultiplication` `(``0.00``s``)`
`PASS````

That’s the magic word: we made our test `PASS`!

## JavaScript

In `test_money.js`, right after the `const assert = require('assert');` line, define an empty class named `Dollar`:

````class` `Dollar` `{`
`}````

When we run the `test_money.js` file now, we get an error:

``TypeError``:` `fiver``.``times` `is` `not` `a` `function``

Progress! The error clearly states that there is no function named `times` defined for the object named `fiver`. So let’s introduce it inside the `Dollar` class:

````class` `Dollar` `{`
`times``(``multiplier``)` `{`
`}`
`}````

Running the test now produces a new error:

``TypeError``:` `Cannot` `read` `property` `'amount'` `of` `undefined``

Our test expects an object with a property `amount`. Since we’re not returning anything from our `times` method, the return value is `undefined`, which does not have a `amount` property (or any other property, for that matter).

###### Tip

In the JavaScript language, functions and methods do not explicitly declare any return types. If we examine the result of a function that returns nothing, we’ll find the return value is `undefined`.

So how should we make our test go green? What’s the simplest thing that could work? How about if we always create an object representing 10 USD and return it?

Let’s try it out. We add a `constructor` that can initializes objects to a given amount and a `times` method that obstinately creates and returns “10 USD” objects:

````class`` ``Dollar`` ``{````
````constructor``(``amount``)`` ``{`` ` ```
````this``.``amount`` ``=`` ``amount``;`` ` ```
````}````

````times``(``multiplier``)`` ``{`` ` ```
````return`` ``new`` ``Dollar``(``10``)`` ` ```
````}````
````}```` The `constructor` function is called whenever a `Dollar` object is created Initialize the `this.amount` variable to the given parameter The `times` method takes a parameter Simple implementation: always return 10 dollars

When we run our code now, we should get no errors. This is our first green test!

###### Important

Because `strictEqual` and other methods in the `assert` package only produce output when the assertions fail, a successful test run will be quite silent with no output. We’ll improve this behavior in Chapter 6.

## Python

Since `'Dollar' is not defined`, let’s define it in `test_money.py` before our `TestMoney` class:

````class` `Dollar``:`
`pass````

When we run our code now, we get an error:

``TypeError``:` `Dollar``()` `takes` `no` `arguments``

Progress! The error is clearly telling us that there is currently no way to initialize `Dollar` objects with any arguments, such as the `5` and `10` we have in our code. So let’s fix this by providing the briefest possible initializer:

````class` `Dollar``:`
`def` `__init__``(``self``,` `amount``):`
`pass````

Now the error message from our test changes:

``AttributeError``:` `'Dollar'` `object` `has` `no` `attribute` `'times'``

We see a pattern here: our test is still failing, but for slightly different reasons each time. As we define our abstractions — first `Dollar` and then an `amount` field — the error messages “improve” to the next stage. This is a hallmark of TDD: steady progress at a pace we control.

Let’s speed things up a bit by defining a `times` function and giving it the minimum behavior to get to green. What’s the minimum behavior necessary? Always returning a “ten dollar” object that’s required by our test, of course!

````class`` ``Dollar``:````
````  ``def`` ``__init__``(``self``,`` ``amount``)``:`` ` ```
````    ``self``.``amount`` ``=`` ``amount`` ` ```
``````
````  ``def`` ``times``(``self``,`` ``multiplier``)``:`` ` ```
````    ``return`` ``Dollar``(``10``)`` ` ``` The `__init__` function is called whenever a `Dollar` object is created Initialize the `self.amount` variable to the given parameter The `times` method takes a parameter Simple implementation entails always returning 10 dollars

When we run our test now, we get a short and sweet response:

````Ran` `1` `test` `in` `0.000``s`

`OK````

It’s possible that the test may not run in `0.000s`, but let’s not lose sight of the magic word `OK`. This is our first green test!

# Cleaning up

Refactoring is the third and final stage of the RGR cycle. We may not have many lines of code at this point, however, it’s still important to keep things tidy and compact. If we have any formatting clutter or commented out lines of code, now is the time to clean it up.

More significant is the need to remove duplication and make code readable. At first blush, it may seem that in our fewer than two dozen lines of code, there can’t be any duplication. However, there is already a subtle yet significant bit of duplication.

We can find this duplication by noticing a couple of quirks within our code:

1. We have written just enough code to verify that “doubling 5 dollars should give us 10 dollars”. If we decide to change our existing test to say “doubling 10 dollars should give us 20 dollars" — an equally sensible statement — we will have to change both our test and our `Dollar` code. There is a dependency, a logical coupling, between the two segments of code. In general, coupling of this kind should be avoided.

2. In both our test and our code, we had the magic number `10`. Where did we come up with that? We obviously did the math in our heads. We realize that doubling 5 dollars should give us 10 dollars. So we wrote `10` in both our test and in our `Dollar` code. We should realize that the `10` in the `Dollar` entity is really `5 * 2`. This realization would allow us to remove this duplication.

Duplicated code is often the symptom of some underlying problem: a missing code abstraction, or bad coupling between different parts of the code. 2

Let’s remove the duplication and thereby get rid of the coupling as well.

## Go

Replace the `10` in the `Times` function by its equivalent `5 * 2`:

````func` `(``d` `Dollar``)` `Times``(``multiplier` `int``)` `Dollar` `{`
`return` `Dollar``{``5` `*` `2``}`
`}````

The test should still be green.

Writing it this way makes us realize the missing abstraction. The hard-coded `5` is really `d.amount` and the `2` is the `multiplier`. Replacing these hard-coded numbers with the correct variables gives us the non-trivial implementation:

````func` `(``d` `Dollar``)` `Times``(``multiplier` `int``)` `Dollar` `{`
`return` `Dollar``{``d``.``amount` `*` `multiplier``}`
`}````

Yay! The test still passes, and we have removed the duplication and the coupling.

There is one final bit of cleanup.

In our test, we explicitly used the field name `amount` when initializing a `Dollar` struct. It’s also possible to omit field names when initializing a struct, as we did in our `Times` method. 3 Either style — using explicit names or not using them — works. However, it’s important to be consistent. Let’s change the `Times` function to specify the field name:

````func` `(``d` `Dollar``)` `Times``(``multiplier` `int``)` `Dollar` `{`
`return` `Dollar``{``amount``:` `d``.``amount` `*` `multiplier``}`
`}````
###### Tip

Remember to run `go fmt ./...` periodically to fix any formatting issues in code.

## JavaScript

Let’s replace the `10` in the `times` method by its equivalent `5 * 2`:

```    `times``(``multiplier``)` `{`
`return` `new` `Dollar``(``5` `*` `2``)`
`}````

The test should still be green.

The missing abstraction is now clear. We can replace `5` with `this.amount` and `2` with `multiplier`:

```    `times``(``multiplier``)` `{`
`return` `new` `Dollar``(``this``.``amount` `*` `multiplier``);`
`}````

Yay! The test is still green, and we have eliminated the duplication and the coupling.

## Python

Let’s replace the `10` in the `times` method by its equivalent `5 * 2`:

```  `def` `times``(``self``,` `multiplier``):`
`return` `Dollar``(``5` `*` `2``)````

The test stays green, as expected.

This reveals the underlying abstraction. The `5` is really `self.amount` and the `2` is the `multiplier`:

```  `def` `times``(``self``,` `multiplier``):`
`return` `Dollar``(``self``.``amount` `*` `multiplier``)````

Hooray! The test remains green, and the duplication and the coupling are gone.

# Committing our changes

We have finished our first feature using TDD. Lest we forget, it’s important to commit our code to our version-control repository at frequent intervals.

A green test is an excellent place to commit code.

In a shell window, let’s type these two commands:

````git`` ``add`` ``.`` ` ```
````git`` ``commit`` ``-m`` ``"chore: first green test"`` ` ``` Add all files, including all changes in them, to the Git index Commit the Git index to the repository with the given message

Assuming code for all three languages exists in the correct folders, we should get a message like this.

````[``main`` ``(``root-commit``)`` ``bb31b94``]`` ``chore:`` ``first`` ``green`` ``test ` ```
````4`` ``files`` ``changed,`` ``56`` ``insertions``(``+``)````
````create`` ``mode`` ``100644`` ``go/go.mod````
````create`` ``mode`` ``100644`` ``go/money_test.go````
````create`` ``mode`` ``100644`` ``js/test_money.js````
````create`` ``mode`` ``100644`` ``py/test_money.py```` The hex number, `bb31b94`, represents the first several digits of the unique “SHA hash” associated with the commit. It will be different for every person (and every commit)

This indicates that all our files are safely in our Git version-control repository. We can verify this by executing the `git log` command on our shell, which should produce output similar to the following:

````commit`` ``bb31b94e90029ddeeee89f3ca0fe099ea7556603`` ``(``HEAD`` ``->`` ``main``)`` ` ```
````Author:`` ``Saleem`` ``Siddiqui`` ``...````
````Date:``   ``Sun`` ``Mar`` ``7`` ``12:26:06`` ``2021`` ``-0600````

````chore:`` ``first`` ``green`` ``test`` ` ``` This is the first commit, with its full SHA hash This is the message we typed for our first commit

It’s important to realize that the Git repository to which we have committed our code also resides on our local file system. (It’s inside the `.git` folder under our TDD_PROJECT_ROOT). While this doesn’t save us from accidental coffee spills on our computer (always use lids), it does provide assurance that we can go back to a previous known good version if we get tangled up somewhere. In Chapter 13, we’ll push all our code to a GitHub repository.

We’ll use this strategy of committing our code to our local Git repository in each chapter, using the same set of commands.

###### Important

We will use the two commands `git add .` and `git commit -m _commit message_` to commit our code frequently in each chapter.

The only thing that’ll vary is the commit message, which will follow the semantic commit style and include a short, one-line description of the changes.

# Where We Are

This chapter introduced test driven development by showing the very first RED-GREEN-REFACTOR cycle. With out first tiny feature successfully implemented, let’s cross it off. Here’s where we are in our feature list:

 5 USD x 2 = 10 USD 10 EUR x 2 = 20 EUR 4002 KRW / 4 = 1000.5 KRW 5 USD + 10 EUR = 17 USD 1 USD + 1100 KRW = 2200 KRW

Let’s take a moment to review and savor our code before we move on to the next challenge.

## Go

Here’s how the file `money_test.go` looks right now:

````package` `main`

`import` `(`
`"testing"`
`)`

`func` `TestMultiplication``(``t` `*``testing``.``T``)` `{`
`fiver` `:=` `Dollar``{``amount``:` `5``}`
`tenner` `:=` `fiver``.``Times``(``2``)`
`if` `tenner``.``amount` `!=` `10` `{`
`t``.``Errorf``(``"Expected 10, got: [%d]"``,` `tenner``.``amount``)`
`}`
`}`

`type` `Dollar` `struct` `{`
`amount` `int`
`}`

`func` `(``d` `Dollar``)` `Times``(``multiplier` `int``)` `Dollar` `{`
`return` `Dollar``{``amount``:` `d``.``amount` `*` `multiplier``}`
`}````

## JavaScript

Here’s how the `test_money.js` file looks at this point:

````const` `assert` `=` `require``(``'assert'``);`

`class` `Dollar` `{`
`constructor``(``amount``)` `{`
`this``.``amount` `=` `amount``;`
`}`

`times``(``multiplier``)` `{`
`return` `new` `Dollar``(``this``.``amount` `*` `multiplier``)`
`}`
`}`

`fiver` `=` `new` `Dollar``(``5``);`
`tenner` `=` `fiver``.``times``(``2``);`
`assert``.``strictEqual``(``tenner``.``amount``,` `10``);````

## Python

Here’s how the `test_money.py` file looks right now:

````import` `unittest`

`class` `Dollar``:`
`def` `__init__``(``self``,` `amount``):`
`self``.``amount` `=` `amount`

`def` `times``(``self``,` `multiplier``):`
`return` `Dollar``(``self``.``amount` `*` `multiplier``)`

`class` `TestMoney``(``unittest``.``TestCase``):`
`def` `testMultiplication``(``self``):`
`fiver` `=` `Dollar``(``5``)`
`tenner` `=` `fiver``.``times``(``2``)`
`self``.``assertEqual``(``10``,` `tenner``.``amount``)`

`if` `__name__` `==` `'__main__'``:`
`unittest``.``main``()````

In Chapter 2, we’ll speed things up by building out a couple more features.

1 The three dots in "`go test -v ./...`" and "`go fmt ./...`" are to be typed literally; the only instances in this book where they do not stand for omitted code!

2 Kent Beck’s opinion is worth quoting here: “If dependency is the problem, duplication is the symptom.”

3 If there are multiple fields in the struct — which we currently do not — then either the order of the fields must be the same in both struct definition and initialization or field names must be specified during struct initialization. See https://gobyexample.com/structs

• No Comment
..................Content has been hidden....................