Needles to say, the testcode is trivial. This test will fail the preconditions many times and it is therefore wise to crank up the amount of times the test is run by using eqc:numtests/2 where the first argument is an integer, the amount of tests, and the second argument is a property. The modified code becomes

I invite you to run the modified version. Now, for the slightly more complicated sub_min/2 function. While doing the test for sub_min/2, I found a bug in the old implementation, this was the error produced while running the test

The reason is that hms2m/1 produced a float value! And float values don’t work with div. So, what is needed is to either round the return value from hm2m/1 or to make it return a rounded value. As the clock library is intended to work with natural numbers, it’s best to make the functions return rounded whole values. Now, changing the hms2s/1, hms2m/1 and hms2h/1 functions will require changing the tests. Which is kind of the point of having the tests in the first place. Changing the implementation should alert the programmer that the behaviour has changed. Now the test looks like

This time due to the fact that the model in the QuickCheck test will round the Right Hand Side (RHS) and calculate the LHS without rounding! Clearly, we can’t use the m2hms/1 for this test. The solution is to go by the smallest possible unit, the second.

Of course I made proper changes to the other tests in order to keep all functions to returning whole integer values (not using round!) [left as an exercise].

Now it is left to write a test for the add/2 function, the add function will allow us to add two time() values together, wrapping on 24, so the added value is in the bounds of time() as well.

Due to the intended cyclic behaviour on 24, we will have to make adjustments to the other functions first. Making sure everything is working within the bounds of the 24 hour system (00:00:00 – 23:59:59). This minor modification just means adding some (rem 24) to the _2hms/1 functions and changing some tests. Do this first.

End of this story! We now have the clock lib for working with time() values. Now follows the full code. And next time we will start refactoring and tidying up the clock lib, also the testfile, and write our own generators to make the clock_eqc.erl look better.

6 Comments

Hans Törnqvist

What about support for positive leap seconds? As an a-functional programmer (I am not really anti imio), the clock code looks like corrupt apples so I am not sure how that occasional extra second would be handled, but the test looks suspicious.

Positive leap seconds? I had to google it to know what you meant :)http://en.wikipedia.org/wiki/Leap_second
No, I am sorry to say that this clock lib is only defined for 24 hour systems and guarantees nothing outside of that.

I did not have any hidden agenda in my first comment, but it may be worth noting in the article that some research should go into designing tests based not only on “the code”, but on real world influences as well. That is of course essential for good tests and perhaps not immediately relevant to this particular article, but pointing out pedantic details early may guide readers into spending some extra brain cycles when writing tests. Footnote? Future article? “Robust tests for interaction with the ambiguous and random behavior of some human beings”…

Or you can leave it to commentators and hope that your guests have not been damaged by the digg and youtube commentator phenomena.

Well, in Erlang we adopt the “Crash often – crash early” and “Assume it is clean” approaches for (some parts of) development. This is adopted here as well, and Ergo: This library does not promise anything outside of its domain of operation. If the users wish to supply broken input data – they have nothing else to expect but broken output data.

In robust Erlang systems, it is also common to have single points of entry, where the “Ambiguous” and “Random” behaviour can entry the system. In these points it is usual to have very strict filters/logic which can handle such data. Of course such modules should be tested with such “ambiguous” and “random” behaviour in mind.

I agree that tests must be written according to specifications, so I am referring to problems in the specifications rather than the testing. Slightly off topic for your blag possibly :) The specifications do not take into account a real world detail which may cause weird problems down the road. Who is normally responsible for writing or reviewing reliable specs?

This discussion has become rather general about TDD, perhaps we should finish this “off the record” and summarize with one last reply here for anybody interested? Who knows, this may turn into a raging flame war any second, I am a living breeding ground for those (I’ve had bad experiences online…).

In “traditional” projects, there will be an architect that sets the design, from beginning to end. That person would need to think about potential problems. But assuming that the “Hard shell soft interior” view is correct, then no special consideration has to be taken for extremely weird inputs, such input should be sieved and cleaned by the Hard shell.