I’m learning JavaScript (again, and for real this time, I hope). After reading JavaScript: The Good Parts and several online pages, I set out to try some basic TDD in JavaScript. For these instructions (and the soon to be created instructional video), I’m using the following tool set:
Chrome (configured for auto updating)
Terminal (OS X Lion)
Java (to execute use the test runner)
Eclipse (to edit my files)
ViPlugin in Eclipse
This is my first stab at this and I hope to both get a better workflow and better at JavaScript.
For convenience, I copied the downloaded JsTestDriver jar to this directory. The name of the version I downloaded is: JsTestDriver-1.3.3d.jar
Create basic configuration file:
jsTestDriver.conf
In a separate terminal instance, start the test runner:
Open up browser/create a tab and then browse to localhost:9876.
Click on the Capture This Browser link. You’ll see a window with the following information:
First Test: Initial X Value is 0
Create a first test in the src-test directory:
src-test/rpn_calculator_test.js
Run your tests (they fai):
The system complains that the pattern “- src/*.js” does not match any files. So fix that:
src/rpn_calculator.js
Make a directory called logs and send (JUnit-formated XML-based) test output results there:
The resulting log file on my machine:
Next Test: Last Value Entered is X
Add a second test:
append to src-test/rpn_calculator_test.js
See the tests fail:
Add the missing method (and update the implementation a touch):
src/rpn_calculator.js
Run the tests, see the pass:
Refactor the rpn_calculator function, hide value:
Check, tests still pass?
Refactor the tests, remove duplication (this is multiple refactorings on my end):
Verify the tests still pass:
Can Handle Multiple Numbers Entered
Now create a new test:
Appended to src-test/rpn_calculator_test.js
This test will fail because there is no drop() method nor is this functionality supported.
After a little effort, we have this:
src/rpn_calculator.js
And the test are back to passing:
One More Check
Notice the feature envy in the x function? I uses values the variable, the length of values and also has direct knowledge that the size is 0-based. This is not a huge deal, but there are defects in the system as written. Here’s a test to demonstrate a problem:
Notice the failing test:
On both of my 2 HP calculators, I can drop all day long and nothing much happens (somewhat simplified, but reasonable for this demonstation. Conceptually, the so-called (by the documentation) “operand stack” is never empty. Here’s a way to implement that:
Update x method
This gets the job done but now this method is exhibiting feature envy even stronger:
It checks the length twice
It knows that the array is 0-based
It uses “value.” twice and values 1, so values three times.
A typical fix for feature envy is to push the responsibility into the object that has the data. To do that, we’ll introduce a new object: rpn_stack.
rpn_stack
We’ll begin with a few TDD cycles:
rpn_stack_test.js
This fails (there’s no rpn_stack() function:
Fix this by making one and giving it an implementation:
Now the tests pass:
Next, we want to make sure that the last value entered is the one that pop returns:
Append new test to rpn_stack_test.js
This fails, so fix it:
Check that it works:
Do these tests seem familiar? They are almost straight out of src-test/rpn_calculator_test.js. Along those lines, here’s a check similar to the last one we wrote on rpn_calculator:
Run the tests, you’ll notice you the result is undefined instead of 0. This is a quick fix:
Run the tests, you should be back to passing.
A quick check of rpn_calculator.js and you’ll notice that while there’s a use of “.length”, this has been pushed into the new rpn_stack class. However, there’s also a need to get the top without removing it. So two more TDD cycles:
And top version 1:
Then something similar to what we did for pop:
And a fix:
Notice that there’s some duplication between top and pop. When I know JavaScript well enough, I’ll remove it. Until then, let’s use this new object in rpn_calculator.
Using rpn_stack in rpn_calculator
Make a few updates to the rpn_calculator class:
Run the tests, everything should be passing. Here’s the full version of rpn_stack.js:
Comments