Step 2 - The core functionality
Last updated
Last updated
My approach to writing new software is to always do the most important thing first and get it done before I move on to other, less important, functions. What is the core functionality of this application? I would argue that creating an ATM that has some funds is the first thing that we should focus on. If there is no ATM you will not be able to do a withdrawal, right? And it the ATM has no funds you won't be able to get any cash from it either.
The user story:
So let's start with creating a ATM
class and assign some funds to each ATM
that we create. You already know a little bit about classes from the .
Since we are working with TDD, we start with creating a test file first.
As a reminder, It is important that we agree on three things at this point.
Your tests/specs are placed in the spec
folder
Your implementation (or production code) are placed in the lib
folder
Your settings (like Gemfile, etc.) are placed in the main project folder
Alright?
Okay, moving on... Create a new file named atm_spec.rb
in your spec
folder.
Let's add the following test to that file. Note the keywords describe
and it
. Also, as in all ruby programs we are creating blocks with the do
and end
keywords. Make it a habit that you always add an end
if you type do
.
!FILENAME spec/atm_spec.rb
Make sure that you run that spec from your terminal.
What will follow now is a series of steps that aims at showing you how testing can drive your development. In the future you will probably skip some of this steps but for now, bear with me.
If you examine the terminal output, you'll see a line like this one.
That means that the spec file can not load ./lib/atm.rb
(where we are supposed to have our implementation code).
Of course not, we haven't created that file yet. There's no lib
folder yet either. Let's create all that now.
Run your spec again.
A new error message. But not the same as before. That is good. So what have we here? uninitialized constant Atm
? Yes, there is no Atm
class defined. Let's do that.
!FILENAME lib/atm.rb
Let's have another go at the spec.
New error message? Cool!
!FILENAME lib/atm.rb
Another go at the spec and another error message.
Okay, so we expected funds
to be 1000
but it was nil
. Let's make it so that every time an ATM object is instantiated the balance is automatically set to 1000.
We can do that by setting that value in the initialize
method. initialize
is a constructor method that will be run every time an instance of a class is created.
!FILENAME lib/atm.rb
And now, when you run RSpec, the test passes.
Yay! First success! Green is GOOD!
Lesson learned: Every feature, no matter how small, will lead to a series of failures. Until it doesn't. This goes for new, inexperienced programmers, as well as for those of us who has been doing this for a long time. There's nothing wrong with you. Just get used to it and see everything you do as a learning experience.
Keep your calm, read the error messages that RSpec so kindly throws at you and make small steps forward. Be thankful that you have a testing framework that helps you to figure out what is wrong with your code. Imagine if you were coding without it?
Alright, enough of coding philosophy. Let's move on. This is a great time to do a commit and push up your code (Unless you already did that).
Let's add another test to the atm_spec
. Inside the describe Atm
block, add this spec.
!FILENAME spec/atm_spec.rb
In my spec file that it
block starts at line 7. What I can do is to run JUST that particular block, instead of the entire spec file. It might seem trivial right now, but further down the road we'll have dozens of specs and trust me, you don't want to keep running them all at once.
Shoots! New error. Yes, yes, yes. That is supposed to happen! ;-)
So, we have an undefined method 'withdraw'
. Alright. let's create the withdraw
method and let it take one argument - the amount we want to withdraw from the Atm.
!FILENAME lib/atm.rb
Run RSpec just to see another error message.
Okay, I think you get the point now. We don't have to follow the error messages in such detail from now on.
Let's add some functionality to the withdraw
method that actually adjust the balance
.
!FILENAME lib/atm.rb
And when you run RSpec again, the test passes. Another one bites the dust!
Yes, there is no method funds
for the Atm
class. Let's add that by adding a attr_accessor :funds
to the class. What is attr_accessor
? You can read about it in this .