Interface-Based Injection and Test Automation in BC

In this Areopa Academy webinar, Luc van Vugt (fluxxus.nl), author of Automated Testing in Microsoft Dynamics 365 Business Central, explains interface-based dependency injection in AL and how it makes Business Central code testable. David Singleton moderates. Luc walks through what interfaces are, how dependency injection works with them, and then demonstrates the concept live with two examples: a simple name-formatting extension and a more realistic scenario that validates EU VAT registration numbers through an external web service.

Why interfaces?

Luc opens with a recap of a slide from Tobias Fenster’s earlier Areopa webinar on interfaces, using the base application’s price calculation logic as an example. Interfaces let you swap one implementation of a component for another — for example, switching from a standard price calculation to an advanced one with forecasting — without removing or bypassing the existing code.

Slide showing why interfaces matter: swapping a price calculation component in the base application
▶ Watch this segment

He summarizes the value of interfaces around three ideas: componentization (define what a component does, not how), the ability to replace a component at runtime or design time, and the ability to extend a component by adding a new implementation.

📖 Related webinar: Interfaces in AL — Tobias Fenster (Areopa Academy) — the earlier session this webinar builds on, covering the introduction of interfaces in AL. Tobias also wrote up the concept on his blog: Interfaces in AL and why that matters.

What are interfaces?

An interface in AL is a syntactical contract: it defines a method signature — name and parameters — without an implementation. A codeunit implements the interface by providing a non-abstract version of that method. Luc points to the long-standing pattern of a codeunit’s OnRun trigger, referenced by a table field, as an early form of the same idea — except that with interfaces and enums, only specific, deployed implementations can be selected, rather than any arbitrary codeunit ID.

AL code slide defining the INameFormat interface as a contract with a FormattedName method
▶ Watch this segment
📖 Docs: Interfaces in AL — Business Central | Microsoft Learn — the official reference on interface syntax, implementation, and linking implementations to enum values.

Demo: formatted name

Luc demonstrates the concept with a small example: a Person table extended with an INameFormat interface. Different codeunits implement FormattedName differently — first name only, last name only, or a full-name concatenation. An enum on the person record selects which implementation runs, so switching the enum value switches the formatting logic without touching the calling code.

Visual Studio Code showing the INameFormat interface AL source file
▶ Watch this segment

He then shows this live in Business Central: selecting different name-format options on a person record produces different formatted names, backed by an enum extension he added with two extra implementations — a Mock and a Stub — used later for testing.

Business Central Persons list showing different formatted names produced by different interface implementations
▶ Watch this segment

Dependency injection

Dependency injection is the general technique of replacing a hard-coded dependency — a call to a specific table or codeunit — with one that can be swapped out. Interfaces provide an AL-native way to do this: instead of referencing a codeunit ID directly, code calls a method defined by an interface, and an enum value determines which implementation actually runs.

Slide summarizing interface-based dependency injection, componentization, and testability
▶ Watch this segment

Luc calls out that this decoupling is valuable beyond just swapping production logic — it’s what makes code testable, because a test can inject a different implementation than the one used in production.

Test doubling

A test double is a stand-in for a real component, a term coined by Gerard Meszaros (author of xUnit Test Patterns) as a parallel to stunt doubles in film. A mock is a specific kind of test double with logic that can return different results depending on context, while a stub (often loosely called “mock” in Microsoft’s own test libraries) always returns the same, hard-coded result.

Slide defining test doubles, mocks, and their origin from Gerard Meszaros' xUnit Test Patterns
▶ Watch this segment

Test doubling is especially useful when code calls an external service: it avoids test failures caused by the service being unavailable, avoids the cost or load of repeated calls, and removes the wait time of a real network round-trip. It applies to data as well — hard-coding a set of ledger entries instead of posting through a journal can save setup time in a test.

Demo: VAT VIES validation

The main demo re-implements the standard Business Central flow for validating EU VAT registration numbers against the EU’s VIES (VAT Information Exchange System) service. In the book, Luc solved test isolation for this same scenario by redirecting a codeunit ID and subscribing to an event; in this webinar he re-implements the standard on-run-trigger codeunit as an interface implementation instead, so an enum value can switch between the real service call and a test double.

Flowchart of the VAT registration number validation process calling the EU VIES service
▶ Watch this segment

Live in Business Central, entering a valid Dutch VAT number triggers a real call to the EU VIES service and returns the registered company name and address — visibly slower than the mocked version, since it waits on a network response. Switching the VAT Validation Handling Type enum to a stub implementation returns an immediate, hard-coded response without calling the service at all.

In code, the interface defines a single contract method, CheckandLogVATNo. The production implementation calls the real VIES SOAP endpoint. The test app adds an enum extension with two additional implementations: an invalid-response stub that returns a “not found” result, and a valid-response stub that builds an XML response with data generated by AL’s Any test library, so each test run gets fresh, unique values.

AL code for the Invalid VIES Check codeunit implementing a mock of the VAT validation interface
▶ Watch this segment

Finally, Luc shows two automated tests — one for a valid VAT number, one for an invalid one — that each set the VAT Validation Handling Type enum to the corresponding test double before calling the same validation logic. Because no real service call is made, both tests run in well under 10 milliseconds.

AL test codeunit with valid and invalid VAT registration number tests using dependency injection
▶ Watch this segment

Resources and Q&A

Both examples from the webinar — the person name-format extension from BC TechDays 2022, and the VAT VIES validation example — are published on Luc’s GitHub.

GitHub repository page for fluxxus-nl/ALInterfaceExamples showing the README
▶ Watch this segment
📖 Code: fluxxus-nl/ALInterfaceExamples on GitHub — both demo projects shown in this webinar, plus the BC TechDays 2022 “Advanced topics in test automation” example.
📖 Book: Automated Testing in Microsoft Dynamics 365 Business Central, Second Edition — Luc van Vugt (Packt) — chapters 12 and 13 cover test doubles and testing outgoing calls in more depth, including the codeunit-redirection approach used before adopting interfaces.

During Q&A, Peter Kahn asked what to do if an enum with interface implementations shouldn’t be publicly extensible but still needs to support testing. Luc’s answer: give the test app internal access to the enum. As the owner of the enum, you can grant your own test extension access to it even if you don’t want to expose it for general extensibility.


This post was drafted with AI assistance based on the webinar transcript and video content.