It's been a while that I wrote on NAV and automated tests. In the meanwhile I have been teaching a lot all over Europe, and, yes, advocating test automation in NAV. And what did you do since my last post How-to: Run Standard Tests against Your Code? Did you dare and try? And did you also have the time/guts to continue with it? I know some that did.
In the same meanwhile I succeeded to get MS listen and implement a major request I had posed already some time ago. We'll get to that below as it relates to the topic I would like to talk about here: Test Fixture.
If you have been testing software, and probably you do being in my audience, you know that a major part of your testing effort is getting data prepared to allow you to execute your tests. Having been a tester I dare to claim it is THE major part. Test Fixture is the general term for the setup up your system before you execute your test(s), be it software or hardware.
With respect to NAV test automation I have adopted the three level approach Bas Graaf used in his NAV Tech Days presentation ages ago, which he based on xUnit Patterns:
Applying this to NAV:
When I started the project to get the Dynamics NAV Test Toolkit run on our code as per How-to: Run Standard Tests against Your Code, it was giving this result:
23 % percent of a total of 16.124 NAV 2016 tests where successful. Using a statistical approach, tackling the most occurring issues first, I could raise this to 72 % in less than a week. And mainly by focusing on the lazy setup:
By creating one generic Initialize function of our own:
Initialize() IF NOT IsInitialized THEN BEGIN IsInitialized := TRUE; N4LibraryLabel.CreateLabels; N4LibrarySetup.CreateTNTSetups; N4LibrarySetup.SetCompanyInformation; N4LibrarySetup.SetWarehouseSetup; N4LibrarySetup.SetInventorySetup; N4LibraryERM.CreateVATPostingSetups; N4LibraryERM.UpdateVATProdPostingGroups; N4LibrarySetup.SetPurchaseSetup; N4LibrarySetup.CreateSalesSetups; N4LibrarySetup.CreateVDESetups; N4LibrarySetup.CreateOWSSetups; N4LibrarySetup.CreateOWSCommunicationSetups; N4LibrarySetup.CreateCBSetups; N4LibrarySetup.CreateOWSNumbersSetups; N4LibrarySetup.CreateMultiple3SNoSeries; N4LibrarySetup.CreateTransactionModes; N4LibrarySetup.CreateMultiplePaymentTerms; N4LibrarySetup.CreateTermPeriodDefinitions; N4LibrarySetup.CreateOWSSelections; N4LibrarySetup.CreateReqWorksheetTemplates; N4LibrarySetup.CreateDeliverabilityCodes; N4LibrarySetup.UpdateItems; END;
... that I hooked into the local Initialize function of each test codeunits, like in the following example in COD134126 (ERM Reversal VAT Entries):
LOCAL Initialize() LibrarySetupStorage.Restore; IF IsInitialized THEN EXIT; //<<< N4LibraryInitialize.Initialize; //>>> LibraryERMCountryData.CreateVATData; LibraryERMCountryData.UpdateGeneralLedgerSetup; LibraryERMCountryData.UpdateGeneralPostingSetup; LibraryERMCountryData.UpdateVATPostingSetup; IsInitialized := TRUE; COMMIT; LibrarySetupStorage.Save(DATABASE::"General Ledger Setup");
What the h*ck, lazy setup? Sho-go-nai as the Japanese say, as I learned from Mark Brummel: Nothing can be done about it. Yes, I had to modify 480 test codeunits (of the total of 628) to get this working! And I told MS that I had to. This could have been prevented by a better design of there Initialize function from the start. And yessss, MS listened and now with NAV 2018 CU3 a redesign has been implemented in the first 100 test codeunits:
LOCAL Initialize() //<<< LibraryTestInitialize.OnTestInitialize(CODEUNIT::"ERM Apply Sales/Receivables"); //>>> LibraryVariableStorage.Clear; LibrarySetupStorage.Restore; IF isInitialized THEN EXIT; //<<< LibraryTestInitialize.OnBeforeTestSuiteInitialize(CODEUNIT::"ERM Apply Sales/Receivables"); //>>> LibraryERMCountryData.CreateVATData; LibraryERMCountryData.UpdateAccountInCustomerPostingGroup; LibraryERMCountryData.UpdateGeneralLedgerSetup; LibraryERMCountryData.UpdateGeneralPostingSetup; ModifyGenJnlBatchNoSeries; isInitialized := TRUE; COMMIT; LibrarySetupStorage.Save(DATABASE::"General Ledger Setup"); //<<< LibraryTestInitialize.OnAfterTestSuiteInitialize(CODEUNIT::"ERM Apply Sales/Receivables"); //>>>
where LibraryTestInitialize is COD132250 (Library - Test Initialize) and contains these three event publisher to which we now can subscribe:
[External] [IntegrationEvent] OnTestInitialize(CallerCodeunitID : Integer) [External] [IntegrationEvent] OnBeforeTestSuiteInitialize(CallerCodeunitID : Integer) [External] [IntegrationEvent] OnAfterTestSuiteInitialize(CallerCodeunitID : Integer)
So getting your lazy setup done on standard tests is a no-brainer. Another threshold taken to get test automation going.
Hi Dave,
It's not a matter of better or not, it's a roughly choice between:
We did choose for the first for the very simple reasons:
And yes, we will also write test for our own, specific functionality. As a matter of fact, we have started doing that.
Recently I have been writing test codeunits for our ISV product, so I will take a look at this closer. Our codeunits have been added rather than customize the NAV supplied ones. Do you think it is better to customize the NAV supplied codeunits?
Awesome, Luc.
Thanks Luc, you are truly our NAV Testability Crusader! (Couldn't find a crusader - so strong man emoticon must do)...
That are some very valuable additions! Thanks, man!