Share your knowledge: become at speaker at Days of Knowledge NORDIC.
The main conference is planned on June 17 - 18 in Odense, Denmark and two full pre-conference training days are planned on June 15 - 16.
Call for speakers: Days of Knowledge NORDIC 2022
Share your knowledge: become at speaker at Days of Knowledge NORDIC.
From fresh to shared fixture – a nice display of applying TDD’s 2nd rule #1
In this series of posts I would like to display a very simple, though instructive, example of how easy refactoring works when you have both app and test code at your disposal. And at the same time I will show you the power of starting coding from specific and gradually moving to generic (and not the other way around).
But before “going wild” on this let me elaborate on a number of concepts that I will be using below.
Test-Driven Development vs. test automation
As I also discuss in chapter 2 of , many times Test-Driven Development (TDD) and test automation (TA) are used like synonyms. Often I am told by a customer or a course attendee, that their team or company has started using TDD in their daily work. In most cases, inquiring a bit more into the details, it becomes apparent that it’s not so much TDD, but the fact that they have picked up creating automated test. So, more TA than TDD. Indeed TDD makes heavily use of TA, but is much more than that. It’s a programming technique that shapes your development practice. It prescribes how you get from a list of test – defining the behavior of the feature you’re building – to app and test code. Or rather: to test and app code, as in TDD test code is what you build first.
Whatever you think of TDD – you know some get allergic just hearing the term – one of the great things about it is that it’s “a game” with only two rules. Yep, just two rules, and everything else is derived from that.
- Never write a single line of code unless you have a failing automated test
- Eliminate duplication
Rule 1 directly relates to the term TDD: if you write a line, or more, of (app) code there should have been already a failing test available that urges you to write that code. I always image TDD to be a ladder where app code and test code make up the two rails and should not/cannot go too much “out of sync”.
Rule 2 triggers you to refactor your code, or, as the rule points it out, to eliminate any duplication that exists in your code. This rule helps you gradually move from “specific to generic” and is only applied once rule 1 has been fulfilled, not the other way around. Note that there is a valid wider interpretation of the second rule: clean up the code created so far – and nothing more – to make it readable, reusable and minimalistic.
Fresh fixture vs. shared fixture
As you might know from your own experience a bigger share of your time spent on testing and test coding is taken by setting up the data needed to be able to run your test(s). This data setup is also called (test) fixture and can be categorized in three groups or levels based on (see also chapter 5 of my book).
Applying this to Business Central (as I also discussed in ):
- Prebuilt Fixture is the database we will run our tests on.
Typically this is CRONUS, containing all sorts of preset data.
- Lazy Setup or Shared Fixture is the data created at the start of a related number of tests.
Typically is about master, supplemental and setup data used jointly by a number of tests that reside in the same test codeunit.
- Fresh Setup or Fresh Fixture is data created for a specific test only.
So this is data added to the shared fixture needed to execute a specific test. This often entails transactional data and custom master data.
When developing an automated test one of your strives – a TDD attitude – should be to get it passing asap. Meaning that you are inclined to get data setup for that specific test – i.e. fresh fixture – at first not taking into account the broader context of related tests perse. Note that there is nothing holding you from reusing data creator functions that you have applied to previous test all ready if that gets your also passing asap. But … tend to keep it specific and once your test code and app code (change) result in a passing test, you apply rule 2 and can move from “specific to generic”. This can lead fresh fixture to be “promoted” to shared fixture. That’s what I am going to display below.
From fresh to shared fixture – a refactoring example
In my TA courses and workshops I often make use of one of the examples that you can find in the GitHub repo: . This feature consist of two sub features, or so-called ATDD features:
- Unblock Deletion of Whse. Shpt. Line enabled
- Unblock Deletion of Whse. Shpt. Line disabled
Indeed two ATDD features that sound very much akin and probably lead to a number of tests that are also akin. If you have read my book you will know that, in my approach, each feature leads to a test codeunit containing the test functions that implement the scenarios that go with that feature. And if two test codeunits are somewhat similar they probably will have overlapping code parts, i.e. code duplication.
In this refactoring example I will start at the point where the scenarios of the first feature only have been implemented and not all duplication has been eliminated. We will first exercise rule 2 on this codeunit and then start working on the second feature. Doing the latter we and getting the test pass asap we will introduce another bunch of duplications.
Stay tuned for the next episode in this series.
Business Central Power BI Multi Environment template
Errata and Updates to my book and GitHub project (2nd edition)
Like any other kind of project writing and publishing a book never leads to a 100% flawless result, whatever the level of commitment and professionalism. My peers and I have spend so much time in getting things reviewed and modified. Alas, it might seem useless but of course isn’t. I am grateful we did catch various things and could get them improved. Not just typos or grammatical errors. Also necessary clarifications and additional information.
Starting to read the book myself as a source to my work I already have stumbled over a number of incongruities which I marked in my copy. Now it’s time to share to most relevant ones with you to enable you to get tour doubts addressed. Where I will not be able to update your copy of the book I will make sure that any anomaly in the code or any of the documents shared on the repo will be updated.
As promised on the same I will be updating this topic, so, keep an eye on it, if you want to be updated too.
Chapter 2 – Figure 2.1 – The red-green-refactor mantra (page 20 in e-book)
A small update was needed in the flowchart displayed in Figure 2.1. Note the difference in the following two images, where the first one displays the original version and the second the fixed, newer one.
The on GitHub has been updated accordingly.
Chapter 11 – Deconstructing your scenario – steps 1, 2, 3, and 4 (page 284 in e-book)
In the note a very unfortunate typo happened here: the words now a should have been no.
Creating, maintaining, and executing a consecutive sequence of dependent tests has
a couple of challenges as there is no formal way to link them together and enforce
their execution to be always a complete run of these tests.
If you have any question and errata/updates to report feel free to do so below, and even though I am not listing any grammatical omission above you’re welcome to provide them too
Multi-line text search in VSCode (with RegEx)
Business Applications Cloud Week for Partners, February 28-March 4, 2022
REST API integration in S2S (Service to Service)
Addendum #02 – Including all extended pages in permissions testing
As promised in my first addendum post I would pick up one-by-one the out-scoped issues logged on the GitHub repo accompanying the book. This one took a bit longer because of my needed Xmas break and the fact that this one would need some to time get it done.
What was missing?
In chapter 8, test example 9, I discuss how to test permissions. In the context of the LookupValue case these tests can be divided into two groups:
- Accessing the data, that is reading, inserting, modifying and deleting the data in the tables of our extension, being actually only one table:
Lookup Valuetable. I call this direct data access.
- Accessing the controls that relate to the data, being the
Lookup Value Codefield control on the various page extensions. I call this indirect data access.
The direct data access – first group – is addressed fully in the book. The indirect data access – second group -, however, only partly. This was due to the fact that this concerns altogether 36 pages and was too much work with too little importance to get it done at that time. I did define and implement the four following scenarios – for two pages – as examples to the rest:
[SCENARIO #0051] Check lookup value on customer card without permissions
[SCENARIO #0052] Check lookup value on customer card with permission
[SCENARIO #0053] Check lookup value on customer list without permissions
[SCENARIO #0054] Check lookup value on customer list with permissions
The permission tests for the other 34 pages were out-scoped and parked .
How was it fixed?
Finally, yesterday, I sat down to get the remaining permission tests done. 34 pages, 2 tests each, making up 68 tests! Wow, how to get this completed in as little as possible time?
Well, by extending the with the 68 additional tests scenarios and making use of the that I discuss in chapter 9.
I decided to number these scenarios starting from 0300 as it would not fit in between the numbers used so far, Note that I often do use higher numbers for scenarios that are added later to make clear that the collection of scenarios is never complete. Scenarios keep on added later due to better understanding, reported omissions, etc.
Creating those 68 scenarios is a matter of copy-pasting the four example scenarios listed above and making use of some Excel functions to easily apply the relevant page names. This all leads automatically to relevant texts in the ATDD.TestScriptor Format columns input to the ATDD.TestScriptor module.
The test codeunit generated – this is the final result: – I completed by adopting some code from it’s and doing an additional round of copy-pasting. Yep, there is not a lot of reusability in this final result due to the fact that each page needs to be addressed by a unique
In about 3 hours I added 68 tests – not a bad performance with less than 3 minutes per test – which are, due to my repo and pipelines setup, automatically executed in any next pipeline run.
These are the two tests for the
Blanket Sales Order page:
procedure CheckLookupValueOnBlanketSalesOrderWithoutPermissions() var BlanketSalesOrder: TestPage "Blanket Sales Order"; begin //[SCENARIO #0300] Check lookup value on Blanket Sales Order without permissions //[GIVEN] Full base starting permissions SetFullBaseStartingPermissions(); //[WHEN] Open Blanket Sales Order BlanketSalesOrder.OpenView(); //[THEN] Lookup value field not shown VerifyLookupValueNotShownOnBlanketSalesOrder(BlanketSalesOrder); end; [Test] procedure CheckLookupValueOnBlanketSalesOrderWithPermissions() var BlanketSalesOrder: TestPage "Blanket Sales Order"; begin //[SCENARIO #0301] Check lookup value on Blanket Sales Order with permissions //[GIVEN] Full base starting permissions extended with Lookup Value permissions SetFullBaseStartingPermissionsExtendedWithLookupValue(); //[WHEN] Open Blanket Sales Order BlanketSalesOrder.OpenView(); //[THEN] Lookup value field shown VerifyLookupValueShownOnBlanketSalesOrder(BlanketSalesOrder); end;
As both permissions test codeunits use identical helper functions there is clearly a need for refactoring. I decided, however, not to do this as it would introduce too many changes to the existing code and make repo too much different from what was released with the book.
Business Central: Send an appointment from Job Planning Line