TDD in NAV - Test #2

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]

TDD Series Index

  1. Test-Driven Development in NAV - Intro
  2. Test-Driven Development in NAV - Intro 2
  3. Test-Driven Development in NAV - By Example
  4. Test-Driven Development in NAV - Test #1
  5. TDD in NAV - Triangulation
  6. TDD in NAV - Test #2
  7. TDD in NAV - Test #3
  8. TDD in NAV - Test #4
  9. TDD in NAV - ASSERTERROR or IsFalse
Anonymous
Related
Recommended