TDD – Test First: A Javascript Story

You might be wondering a great many things as you begin to read this most epic of epic things. I can only give you some of the answers you seek, and some that you don’t even know you need. I’m mysterious like that.

A while back I made a rather involved step by step example on how to do Test First design. Luckily I took down some good notes, and made a plethora of images to document the whole thing. I’m glad I did, since I did this about 4? months ago. Far beyond my 1 day long term memory. Basically it’s a step by step process on how to Test First validating a string based Social Security Number.

Side Note

Why use JavaScript? Ease and cross platform functionality. It was the easiest choice when making sure I had a language anyone can use. That coupled with the Chrome development tools, any one can debug also.

End Side Note

Now most people would just copy and paste some obscenely long regex string, and call it a day. I’ll assume you aren’t that guy, because if you are; I wish the internet had a door so it could hit your $@@ on the way out.

Why shouldn’t you use regex? Oh I don’t know. Could be have to do with it looking like something I could produce with a keyboard and a nerd rage session. Or it could be that regex is understood by (approximately) .0000000000000001% of the programming population that most of it remains untouched for decades “cause it werkz”. (I’m not bitter though) Not saying all regex is bad, just when it’s used for something as complex as a Social Security Number. Also, it makes for a reasonably short post… which I’ve already wasted 2 minutes (To 5 minutes depending on your reading level) of your life with. Efficient!

So these are the four rules that will be covered here:

1: It will return false if the string is null.
2: It will return false if there are any characters.
3: It will ignore dashes.
5: It will require a length of 9.

Are these all the rules? Sort of. There are actually some government based rules about what can be where, and were I not so lazy I would include them. However, that they even exist makes regex even more convoluted and/or impossible.

1) Folder Structure

  

As you can see, the final folder structure is pretty simple. If you’ve never used Jasmine before, it also is pretty simple. It is here on github, and… pretty simple? There are three files. That’s it. With those files you’ll find an html page to include jasmine

  

Ok since this is test first, a test has to be made first. Boom.

  

As you see, this test calls a method named “is_real_social_security_number”. Only thing is, that method doesn’t exist yet. Fear not, because here it is:

  

Well at least the shell. Why isn’t there code yet? Because right now it’s just about creating just enough to get it to “compile”, or at least in this case get a useful test failure that doesn’t #@!Q$% about a method that doesn’t exist.

RULE 1 – GET THE TEST TO COMPILE

Now when opening the html test page, it looks like thus:

  

RED!!! AHH!!11 That’s useless… or is it? This is an introduction to an important concept:

RULE 2 – GET A FAILURE

I know that seems sort of weird. After all, how often do you actually try to fail? Other than doing a really bad job of painting a room so that you’ll never be asked to again. Well in Test First you want a failure. In fact a success first can cause panic at times, because it might mean that your test is jacked or useless. For example: If I knew my test should expect a non null return based on a specific rule, and I haven’t added the rule yet. If it runs green, than it’s very possible the test isn’t written correctly, or that your tested code is returning something it shouldn’t. Good thing this isn’t true for the current test. Be happy, you can now prove to your mom that failure is good!

Ok now for the next rule:

RULE 2.43 – DO THE ABSOLUTE MINIMUM TO GET IT TO GO GREEN

This is probably the hardest concept to get in testing. The idea is, as the rule suggests, do just enough to get the current test to go green. That is the rule if it is the first or fifth test. So at this point, what will make it go green? Well remember that the first rule is “It will return false if the parameter is null.” So… send it a null, and return a true.

  

Now anyone who isn’t familiar with JavaScript, there is a bit of trickery here. Turns out that if(null) returns false. This makes if(argument) equivalent to if(argument != null). Aaaaaaaand if the test is run again:

  

Weeee green!

Ok so next on the list is: It will return false if there are any characters.

So once again, make the test first and watch it fail:

  
  

What the !@#%? Remember that thing about success sucks sometimes? This is it. Why is it green? The validation method is returning false no matter what, because the return variable in the method is currently hard coded to false. This coupled with the fact that the second test is looking for false makes it go green. (Yes testing for false is OK) Well, that can be fixed:

  

Now the return is always true if the argument is not null, and since texts is being sent through:

  

&*#% yah, failure!

Ok so now there needs to be code to make this go green. Sounds reasonable enough.

  

Ok so that may look a little strange at first. At least past the opening clause. First clause is just a check to make sure that it’s not an empty string. You might be wondering why I’m not checking for null in “contains_a_character”. This method I created is nothing more than an abstraction (Meaning it was taken straight from the main method, and had a method wrapped around it) from the method being tested. Because of that, the main method is checking for nulls. Were the “contains_a_character” method made to stand on its own, then there would most likely be a null check. Just think of the method as a private method. Aaaaand that brings us to another shouting rule:

RULE D – DO NOT TEST PRIVATE METHODS

This is a hard rule to get someone to understand. After all, if private methods aren’t tested, how can one be sure they work? The answer is: Because you’re testing the public method that is using said private method, the test suite by association tests the private methods. If anything is wrong with the private method, it will make the tests for the public one fail. Besides, in this case the “contains_a_character” method is nothing more than taking code out of the main method, and slapping a method signature on it to help with readability.

It also brings up something else… I made an oopsy. Generally method abstractions happen AFTER a green test. That way, you can get the test to go green with the most simple (and possibly inefficient) code. Then when the test goes green, you can optimize/abstract knowing that if you screw up, the test will fail. I’ll forgive myself this time…

Non Sequitur

One small thing that may be of interest is the return line. Most people would have just used a for loop. Start at the first dcharacter, walk each one, and break on the first non number. I am not most people, unless most people are defined as “recursion friendly”. Essentially I call the “contains_a_character” method over and over, with each call taking one character off the original string.

  isNan(currentText[0])

This is used to check just the first character in the string. If it is a non number (NAN) then true is returned. If it is a number:

  contains_a_character(currentText.substring(1))

This lops off the first character in the string (or grabs everything other that the first character), and calls the “contains_a_character” method all over again.

Side Note

Taking the first item of a list is usually referred to as “head”, “first”, or “car”. Taking all but the first is usually refereed to “tail”, “rest”, or “cdr”.

End Note

Do you have to use recursion? Nope. Most languages don’t handle recursion (Tail call to be specific) so you can end up blowing the stack (stack overflow). Not sure that was an appropriate way to phrase that…

In the end, for small string it’s up to you.

End Non Sequitur

Ok so now that’s done with, and as you could see: The parent method now has the “contains_a_character” method being called with the null
check. Time to run that test again.

  

Alright, so now it checks for null and non numbers. Awesome. Two more to go.

Ok, now something to ignore dashes. Personally I’d rather irraticate them all, but they breed like rabbits.

  

Pretty straight forward. Call the method with dashes, and expect it to show more tolerance for dashes than I have. Making the test a better man than I.

Now to run it.

  

And it failed. Please say you weren’t surprised by the result. Now for the code to fix it.

  

Ok so once again there’s some trickery going on here, so I’ll break it down.

  if((plainText = argument ? argument.replace('-', '') : argument))

Ok so that could actually look like this:

  var plainText;
  
  if(argument != null) {
    plainText = argument.replace('-', '');
  }

  if(plainText && !containes_a_number(plainText)

A lot more typing. Because the plainText = ar… part is encased in a pair of parentheses: the statement is run, plainText is given a new value, and that value is evaluated with the rest of the if statement. And since the if statement is done left to right, by the time it gets to the “!contains_a_number(plainText)” section of the if statement, plainText already has its new value.

  

&*#@! Ok so something is wrong. How do I know? I’m smart like that. The question is: Why did it fail? After all, the whole thing is based on the replace method. Time to dive into that. To do that in chrome you need to open the developer tools.

  

OR just press CTRL + SHIFT + J. tHATS… That’s the easier way. Next it’s a trip to “sources” land.

  

What this does is allows a user to view any JavaScript file in use for the page. For the purposes of this train wreck, the non test JavaScript file will be opened. There will be a break point on the return line.

  

Hrmmmmmm still looks like it has dashes in it. Turns out that replace only replaces the first instance. Learned that from the Google. After doing some searching on that, I came across This post. Basically it shows that using replace with a regular expression is the preferable way to remove all the dashes.

  

Although in retrospec, I could have done something like this:

  function removeDashes(stringToCopyFrom cleanedUpText){
    return stringToCopyFrom.length === 0  ? cleanedUpText  : removeDashes(state.substring(1), stringToCopyFrom[0] === '-' ? cleanedUpText : cleanedUpText + stringToCopyFrom[0]);
  }

Once again, this is a recursive call. If the stringToCopyFrom text has no length, return cleanedUpText. What’s cleanedUpText? It’s the string that will grow for every time the method is called recursively. The idea is to construct a new string that has no dashes by walking through the original string, and adding any non dashes to the cleanedUpText string. So for every “iteration” the first character is checked to see if it’s a dash. If it is, then ignore it and pass through the current value of cleanedUpText as the second value of the method call. If it isn’t, then append the current character to the current cleanedUpText, and send that through as the new cleanedUpText value.

The main reason I’m pointing this out is that even though I had decided at the time the solution I had was good (I has = I stole); possible improvements can always be sought. Yes I know, I’m not as perfect as you thought I was.

Now to run.

  

WEEEEEEEEEEEEEEEEEEEEEEEEEE

Now for the last step: Length check. So once again, the test is created first.

  

As you can see, there are three assertions in the one test. It could be argued that they should be three separate tests since it should be a 1:1 ratio. Or it could be argued that even though there are three assertions, they work the same. Another possibility would be to combine all three into one statement by using &&. Apparently once again my laziness got the better of me.

Now to run that @#%&*:

  

Looks like only two failed, as they should have. After all, a string of 9 letters has no reason to fail with the given code. This is another reason why the test could be split up. One that checks to make sure the “happy path” works (9 numbers), and the other to make sure any other length fails.

  

Simple addition of the length check. Now to run the test again:

  

Alright. Hard to type why simultaneously patting myself on the back. So this means we’re done, right? Hell no.The best part is next: Refactoring. The goal will be to abstract away a lot of the code into methods with very English and readable names.

Refactor 1: Impact – slight

Remember that bit where I said there didn’t need to be a null check in the “contains_a_character” method? Still doesn’t, BUT I can get that check for free. Just add the assertion to the test:

  

And then replace the === “” check with the much shorter JavaScript null/empty string check:

  

And run the test:

  

Ok, that’s one down.

Refactor 2: Impact – Questionable

Next is to remove some code from the main method.

  

What happened there? I removed the “isARealSocialSecurityNumber” variable since it only held the result of the truth check. This is questionable since it could be argued that even though the “isARealSocialSecurityNumber” might have been extraneous, it helped convey the intention of the method. Personally, I’m fine with reducing that down to only a truth check.

  

Oh &(%@ no. I dun broke somethin’. For some reason the original test to expect false when passing in an empty string (or null) is now failing. This means that the method is allowing empty strings to pass through. (Hence the “Expected ” to be false” error) Bad. This time we’ll take a trip to jsfiddle land. What is jsfiddle? It’s a site where you can paste JavaScript, and get an immediate result.

  

Just as suspected, the method is returning an empty string instead of a Boolean. Since there no longer is an if statement, the assignment trick fails to return a Boolean on an empty string. The reason being is that since the original if statement actually returned “false” if the string was empty. Now the assignment trick is returning the actual string because of this:

  if(plainText = argument ? ... : argument)

So if the argument is empty, false is evaluated. This means the second half of the ? : will return the actual arugment string. This is not a true/false value.

  

That part of the if statement will now return “false” if the “argument” is empty/null.

  

Yay.

Refactor 3A: Impact – Questionable

Much like the last questionable refactoring, I am combining two truth checks:

  

Now the entire “contains_a_character” is one if statement return.

Refactor 3B: Impact – Great

In that same image you might have noticed there was more to the change. The easiest to notice is the method was renamed from “contains_a_character” to “does_not_contain_a_character”. With that change, the truth check involved was reversed. By doing this, I was able to replace the old “!contains_a_character” with just “does_not_contain_a_character”. This makes the whole thing more readable:

  

This brings up another rule:

RULE IV – DO NOT THINK REFACTORING STOPS AT STRUCTURE CHANGES

Basically, when one is refactoring, one should not just look for code improvements. Renaming methods to make their intention known is incredibly important. Renaming them so they could be understood by those things we call “business analysts” means someone with any experience with reading can immediately pick up what the method is doing.

Refactor I lost count: Impact – Great

  

This is yet another section of the if statement that has been pulled into a method with a very readable name. In fact, if you replace “&&” in your head with the word “and” it reads like:

if .. and does not contain a character and has a valid length

Much nicer than what it was before.

Refactor 0110: Impact – Great

  

One more abstraction, and now even a child could understand. Well a child that can read. Probably not a baby.

  

Yay for the final green.

Now there are more rules for a social security number, but this had been more than enough to waste your time. I’ll spare you from any further harm.