Unit tests
2010-12Dec-06
There are some topics that I've been talking about for years at conferences, user group meetings, in articles, and so forth. One of these topics is code quality. My recent attempt to increase code quality of my fellow developers was the introduction of test-driven development.
To make this a short story: Even after listening to my talk the majority seems to believe that – while this all very nice – in practice writing tests first is way too much for work for too little return. Well, obviously I haven't yet found the best way to get my message across. So, here's another attempt.
If you've been developing in FoxPro for a while you know that Rushmore doesn't work with certain navigation commands, namely GO and SKIP. This makes GO TOP and GO BOTTOM relatively slow commands if a filter is applied to the table that narrows the visible area to just a few records. Both commands will read the entire table from the beginning or the end, respectively, until they encounter the first record that matches the current filter.
The workaround for GO TOP is very easy: You use the LOCATE command. GO BOTTOM is a bit more difficult. You invert the current index order turning the last record into the first record, then you use LOCATE, and finally you revert the index order back to the original one.
Your task for today: Create a procedure GoBottom that navigates to the last record in the current work area using Rushmore and respecting all filters, SET DELETED, and the like. Write the code the same way you would write any other code. BTW, leave HackFox in the shelf. Its code is good, but not good enough.
Now that you've written the procedure, try the following unit tests with your GoBottom procedure (use FoxUnit to create and run the unit tests). Does your GoBottom procedure pass all of them on your first try?
If not, what about writing the unit tests first, next time? Then you wouldn't have released that buggy piece of code.
If you've been developing in FoxPro for a while you know that Rushmore doesn't work with certain navigation commands, namely GO and SKIP. This makes GO TOP and GO BOTTOM relatively slow commands if a filter is applied to the table that narrows the visible area to just a few records. Both commands will read the entire table from the beginning or the end, respectively, until they encounter the first record that matches the current filter.
The workaround for GO TOP is very easy: You use the LOCATE command. GO BOTTOM is a bit more difficult. You invert the current index order turning the last record into the first record, then you use LOCATE, and finally you revert the index order back to the original one.
Your task for today: Create a procedure GoBottom that navigates to the last record in the current work area using Rushmore and respecting all filters, SET DELETED, and the like. Write the code the same way you would write any other code. BTW, leave HackFox in the shelf. Its code is good, but not good enough.
Now that you've written the procedure, try the following unit tests with your GoBottom procedure (use FoxUnit to create and run the unit tests). Does your GoBottom procedure pass all of them on your first try?
If not, what about writing the unit tests first, next time? Then you wouldn't have released that buggy piece of code.
Procedure Test_NoIndexSet
Create Cursor Test (nField I)
Insert into Test Values (1)
Insert into Test Values (2)
Go top
GoBottom()
This.AssertEquals ("fail", 2, Test.nField)
Use
EndProc
Procedure Test_SpaceInPath
Local lcPath
lcPath = GetEnv("temp")+"\Test dir"+Sys(2015)
MkDir (m.lcPath)
Create Table (m.lcPath+"\Test") (nField I)
Insert into Test Values (1)
Insert into Test Values (3)
Insert into Test Values (2)
Index on nField Tag nField
Go top
GoBottom()
This.AssertEquals ("fail", 3, Test.nField)
Use
EndProc
Procedure Test_AscendingIndexSet
Create Cursor Test (nField I)
Insert into Test Values (1)
Insert into Test Values (3)
Insert into Test Values (2)
Index on nField Tag nField
Go top
GoBottom()
This.AssertEquals ("fail", 3, Test.nField)
EndProc
Procedure Test_DescendingIndexSet
Create Cursor Test (nField I)
Insert into Test Values (1)
Insert into Test Values (3)
Insert into Test Values (2)
Index on nField Tag nField
Set Order To nField DESCENDING
Go top
GoBottom()
This.AssertEquals ("fail", 1, Test.nField)
Use
EndProc
Procedure Test_MultipleCdxFilesActive
Create Cursor Test (nField I)
Insert into Test Values (1)
Insert into Test Values (3)
Insert into Test Values (2)
Index on nField Tag nField
Index on nField Tag nField2 of Test.cdx for nField == 2
Set Order To nField
Set Order To nField2
Locate RECORD Reccount()+1
GoBottom()
This.AssertEquals ("fail", 2, Test.nField)
Use
EndProc
Procedure Test_IndexCreatedWithDESCENDING
Create Cursor Test (nField I)
Insert into Test Values (1)
Insert into Test Values (3)
Insert into Test Values (2)
Index on nField Tag nField DESCENDING
Set Order To nField
Go top
GoBottom()
This.AssertEquals ("fail", 1, Test.nField)
Use
EndProc
Procedure Test_IndexCreatedWithDESCENDINGSetToAscending
Create Cursor Test (nField I)
Insert into Test Values (1)
Insert into Test Values (3)
Insert into Test Values (2)
Index on nField Tag nField DESCENDING
Set Order To nField ASCENDING
Go top
GoBottom()
This.AssertEquals ("fail", 3, Test.nField)
Use
EndProc
Procedure Test_JustOneIdxFile
Create Cursor Test (nField I)
Insert into Test Values (1)
Insert into Test Values (3)
Insert into Test Values (2)
Index on nField To Test.idx
GoBottom()
This.AssertEquals ("fail", 3, Test.nField)
Use
EndProc
Procedure Test_CdxFileAndOneActiveIdxFile
Create Cursor Test (nField I)
Insert into Test Values (1)
Insert into Test Values (3)
Insert into Test Values (2)
Index on nField Tag nField2
Index on nField To Test.idx
GoBottom()
This.AssertEquals ("fail", 3, Test.nField)
Use
EndProc
Procedure Test_IdxFileAndActiveCdxFile
Create Cursor Test (nField I)
Insert into Test Values (1)
Insert into Test Values (3)
Insert into Test Values (2)
Index on nField To Test.idx
Index on nField Tag nField2
GoBottom()
This.AssertEquals ("fail", 3, Test.nField)
Use
EndProc
Procedure Test_IdxFileAndCdxTagHaveSameName
Create Cursor Test (nField I)
Insert into Test Values (1)
Insert into Test Values (3)
Insert into Test Values (2)
Index on nField Tag nField2
Index on nField To nField2.idx for nField == 2
GoBottom()
This.AssertEquals ("fail", 2, Test.nField)
Use
EndProc
Procedure Test_IdxFileAndCdxTagHaveSameNameReverse
Create Cursor Test (nField I)
Insert into Test Values (1)
Insert into Test Values (3)
Insert into Test Values (2)
Index on nField Tag nField2
Index on nField To nField2.idx for nField == 2
Set Fullpath on
Set Order To nField2 of (cdx(1))
GoBottom()
This.AssertEquals ("fail", 3, Test.nField)
Use
EndProc