Ouch, keep on singing the RED/GREEN/REFACTOR mantra wasn't that easy the last couple of weeks preparing myself on my NAV Development with Team Foundation Server presentation. But that's past now and I can look forward again. I can go ahead again. Nothing to stop me from getting to GREEN ...
Nothing? Really no thing?
Well, there is one thing I should tackle first as I got a bit mixed-up in my previous TDD post. You know, I wanted to bring in the C/AL statement ASSERTERROR and at the same didn't want to fuzz too much about the missing requirement. I wanted to keep that for a later elaboration.
Although it wasn't really a bad thing, it just wasn't neat and maybe a bit confusing. I could have known then, if I had read the following sentence with a little bit more mindfulness:
The ASSERTERROR keyword specifies that an error is expected at run time in the statement that follows the ASSERTERROR keyword.
So what am I hinting at?
I introduced ASSERTERROR as a means of inverting the result of the Assert.IsTrue statement and it exactly did what I wanted it to do: turn the result from FAILURE to SUCCESS. And indeed the Assert.IsTrue statement is throwing an error. Just have a look in codeunit 130000 (Assert) and see what happens if Condition is false:
IsTrue(Condition : Boolean;Msg : Text)
IF NOT Condition THEN ERROR(IsTrueFailedMsg,Msg)
But this whole Assert codeunit (and the functions it contains) is part of our test framework, and even though its code might throw errors, it doesn't make real sense to test that; in other words: it doesn't make sense to test the test framework. Typically we rather apply ASSERTERROR where it concerns testing the product (code). And we have a perfect alternative available in the same Assert codeunit (130000): IsFalse.
Thus our FailingVerification test function would become:
// Create a purchase headerPurchHeader."Doc. Amount" := 2.5; //Mimic an incorrect manual input of the total doc. amount PurchHeader.INSERT(TRUE);
// Create two purchase lines to the headerCreatePurchLine(PurchHeader."No.",10000,1);CreatePurchLine(PurchHeader."No.",20000,2);
//Check if manually entered total doc. amount does not equal the line amountsAssert.IsFalse(PurchHeader.VerifyDocAmount,'Verify Doc. Amount')
Well, we touched our test code so let's see that it's still working OK. Cross your fingers and ... (6) run test and see it pass:
OK! Do I need to phrase out loud the color? [8-|]
I am a huge fan of Code Contracts, which include Invariants, PreConditions and PostConditions. There is also the big adavntage of Intellisense for contract (or potential contract) violations.Based on work done over the past 3 years [the longest period I have metrics for] , in-depth testing (Contracts, TDD, BDD, etc) has resulted in approximately a 35% reduction in overall cost of development. This takes into account the time invested in writing (and maintaining) the tests and the corresponding reduction in defects found later in the development pipeline.As a side note, I am also in favor of doing the tedious testing [which I refer to as Granular Unit Tests or G.U.T.]. It may seem silly to invest time in testing things like automatic properties, but when a decent automation engine is used to create the tests, there are many benefits.