Wednesday, February 26, 2014

Unit Testing

I just have realized how far is my understanding of unit testing from my expectations.
While I was reading the book Programming Groovy, the strange feeling came that I do not seem to be professional in this area of programming. In the last 6 years I tried hard to make progress in applying Test Driven Development in my projects, but only the last year gave me some kind of peace.
Yeah, it is a process. But it took so long. And still I miss some points.
I am collecting the guides here that were helping me and I am trying to give good overview of some good testing practices.
But before we get lost in the details let us consider the reasons!

Reasoning

Besides the standard few points ("tested code is working", "test make you free to refactor", "prevents returning bugs") there are some more complex benefits of using unit tests.

Deliver Effective Code

The first thing came to my mind was that the code is always write-once-read-many. It is important to write code that is clean and can be read easily. Testing a code with lot of coupling is hard: a lot of mock code must be written and one naturally feels that it is plainly wrong. And it is even more important not to write code that is not used. Tests keep you focused on your main problem (the failing test case) and they help you avoid Featuritis.

Measure Progress

With the constant test-code-check-refactor-check cycle one can be aware of the progress of his coding. Sometimes we get lost in details and dive too deep in coding, that we miss the target. With tests onboard the target cannot be lost.
It also helps to jump into coding and avoid to much procrastination.

Share Knowledge

The unit test is a perfect example for using the given API in the manner as the creator supposed it to be used. All the funny details can be learned from the different test cases. For a programmer the code is the most effective documentation: it is terse, structured and readable.

Gain Knowledge

I also use UT for getting insight on a given API. I formulate my expectations in the form of test cases. And I even gain the possibility to debug the given behavior during real work.
That is how you gain experience by doing something.

(Feel free to add more in comments...)

Ramdisk automation

I have replaced the HDD of my laptop with SSD. The speed increase was amazing. The drawback is that the frequent compilation could use up the storage quickly.
Ramdisk was proposed to be used for cache area of browsers and I have also found some interesting posts about persistent ram disk usage.
The point was to get rid of the frequent update of the files in the target directory of my java projects (that was typically caused by mvn clean install/package).

I have put together a nice little script that replaces the current working directory with an in-memory version. It also takes care of synchronizing back the data every once in a while.

#! /bin/sh 
#
if [ -z "$2" ]
then
  echo "Usage: bin/ramdisk.sh {start|stop|sync} {dir}"
  exit 1
fi
 
case "$1" in
  start)
    mkdir -p /tmp/$2
    rsync -aF $2/ /tmp/$2
    mv $2 $2.save
    ln -s /tmp/$2 $2
    crontab -l | cat - $2/.crontab | crontab -
    ;;
  sync)
    echo [`date +"%Y-%m-%d %H:%M"`] Ramdisk Synched to HD >> log/ramdisk_sync.log
    rsync -aF --delete --recursive --force /tmp/$2/ $2.save
    ;;
  stop)
    echo [`date +"%Y-%m-%d %H:%M"`] Ramdisk Synched to HD and STOP >> log/ramdisk_sync.log
    crontab -l | sed -e "\,$2,d" | crontab -
    rm $2
    rsync -aF --delete --recursive --force /tmp/$2/ $2.save
    mv $2.save $2
    rm -rf /tmp/$2
    ;;
  *)
    echo "Usage: bin/ramdisk.sh {start|stop|sync} {dir}"
    exit 1
    ;;
esac

exit 0

It seems just good enough.
The point is that I put a .crontab file in the working directory, so each project can define its own synchronization policy.
The typical crontab file looks like this:
*/10 * * * * bin/ramdisk.sh sync proj/xpbydoing
Happy ramdisk usage!