Well, don't let us be distracted anymore. Our next test is awaiting us: Test #2.
# |
Description | Status |
1a |
Create PI (purchase invoice) with 1 line and check that total line amount is calculated right | Complete |
1b |
Create PI with 1 line, populate line amount with random value and check that total line amount is calculated right | Complete |
2 |
Create PI with multiple (2) lines and check that total line amount is calculated right | In Progress |
3 |
Create PI with multiple lines and check that doc. amount verification succeeds | |
4 |
Create PI with multiple lines and check that doc. amount verification fails |
Get on with it and …
1. Write our test code
We could do that from scratch, but let's do it efficient (sounds more professional than easy-going, or just plain lazy [:P]).
We already have our first test function PIwithOneLine in codeunit 60000 (Test Doc. Amount) and our second test function will have a lot in common and thus we will create a PIwithTwoLines test function as a copy of PIwithOneLine (you might recall one of my first blog entries on how to copy functions in NAV). Let's just show the code now:
PIwithTwoLines()
// Create a purchase header
PurchHeader.INSERT(TRUE);
// Create two purchase lines to the header
PurchLine."Document No." := PurchHeader."No.";
PurchLine."Line Amount" := 1;
PurchLine.INSERT;
PurchLine."Line Amount" := 2;
PurchLine.INSERT;
//Check if line amounts equals the line amounts calculated by CalcDocAmount
Assert.AreEqual(3,PurchHeader.CalcDocAmount,'Calc. Doc. Amount')
Minimal test code; no fuzz with variables to sum up the line amounts, hard coding suffices here.
2. Compile test code
… which shows GREEN!
Wow, this saves me to have to …
3. Implement just enough to compile
… and hence we can …
4. Run test and see it fail
Indeed, RED:
Did I hear you saying: "You could have known, Luc!"? And right you are: I could have known, but I just wanted to demonstrate that the whole setup is capable of showing me the way. Of course I cannot insert two times the same purchase line, i.e. two purchase lines having the same PK.
As such the code should have been:
PIwithTwoLines()
// Create a purchase header
PurchHeader.INSERT(TRUE);
// Create two purchase lines to the header
PurchLine."Document No." := PurchHeader."No.";
PurchLine."Line No." := 10000;
PurchLine."Line Amount" := 1;
PurchLine.INSERT;
PurchLine."Line No." := 20000;
PurchLine."Line Amount" := 2;
PurchLine.INSERT;
//Check if line amounts equals the line amounts calculated by CalcDocAmount
Assert.AreEqual(3,PurchHeader.CalcDocAmount,'Calc. Doc. Amount')
Let's update and rerun:
RED!
Makes sense? To me it does. The total of the lines is 3 (= 1 + 2), but my CalcDocAmount function (do you recall?) returns the "Line Amount"of the first line only. Here we are again to …
5. Implement just enough to make test pass
Open table 38 in design mode and modify the CalcDocAmount function:
CalcDocAmount() Amount : Decimal
PurchLine.SETRANGE("Document No.","No.");
IF PurchLine.FINDFIRST THEN
REPEAT
TotLineAmount := TotLineAmount + PurchLine."Line Amount";
UNTIL PurchLine.NEXT = 0;
EXIT(TotLineAmount)
Compile and ready to …
(BTW: did I already say that I did declare a variable TotLineAmount of data type Decimal?)
6. Run test and see it pass
… see it pass … [8] … RED/GREEN … RED/GREEN … [8][8] … see it pass? … [8][8][8] … RED/GREEN …
Ready? Run codeunit 60000:
YES … GREEN! … [Y] … [{][}]
7. Refactor
Refactor? Anything to refactor? Looking at both the production and test code …?
CalcDocAmount seems quite OK now. What about our test functions? Have a look at this pattern:
PurchLine."Document No." := PurchHeader."No.";
PurchLine."Line Amount" := …;
…
PurchLine.INSERT;
Looks like we're hitting a duplication (or should we call it a triplication?). RE-FACT-OR! RE-FACT-OR! RE-FACT-OR! RE-FACT-OR! Can you hear the roaring drums?
OK, we'll refactor. Now relax, we will. [A]
1. (Re)write our test code (second time)
What about this?
PIwithOneLine()
// Create a purchase header
PurchHeader.INSERT(TRUE); //TRUE ensures that the system assigns a unique number to the header
// Create one purchase line to the header
CreatePurchLine(PurchHeader."No.",0,1);
//Check if line amount equals the line amount calculated by CalcDocAmount
Assert.AreEqual(1,PurchHeader.CalcDocAmount,'Calc. Doc. Amount')
PIwithTwoLines()
// Create a purchase header
PurchHeader.INSERT(TRUE);
// Create two purchase lines to the header
CreatePurchLine(PurchHeader."No.",10000,1);
CreatePurchLine(PurchHeader."No.",20000,2);
//Check if line amounts equals the line amounts calculated by CalcDocAmount
Assert.AreEqual(3,PurchHeader.CalcDocAmount,'Calc. Doc. Amount')
With a new function (having PurchLine as local variable referring to table 39):
CreatePurchLine(HeaderNo : Code[20];LineNo : Integer;Amount : Decimal)
PurchLine."Document No." := HeaderNo;
PurchLine."Line No." := LineNo;
PurchLine."Line Amount" := Amount;
PurchLine.INSERT;
Now …
2/3. Compile the test code (second time)
… which shows RED. RED? Yes, RED.
[:O]
Never seen that one before. Did you? But I guess that I know what this is about. Did I tell you that any function that we define in a test codeunit by default is of type (FunctionType) Test? Well, that's exactly what happened with our helper function CreatePurchLine:
And Test functions are not meant to be called to in code like Normal functions. So we change FunctionType to Normal, and also set Local to Yes.
Compile … GREEN … and …
4/5/6. Run the test and see it …
… pass! GREEN! Test #2 is completed:
# |
Description | Status |
1a |
Create PI (purchase invoice) with 1 line and check that total line amount is calculated right | Complete |
1b |
Create PI with 1 line, populate line amount with random value and check that total line amount is calculated right | Complete |
2 |
Create PI with multiple (2) lines and check that total line amount is calculated right | Complete |
3 |
Create PI with multiple lines and check that doc. amount verification succeeds | |
4 |
Create PI with multiple lines and check that doc. amount verification fails |
Note
… that, given previous results of our tests and therefor knowing that our production code is OK, refactoring the test code is a pretty save operation to do. [H]