// article
Automated AL tests protect more than individual procedures. They protect the business behavior that must survive extension refactors, dependency changes, and Business Central release waves. A useful test creates a known state, invokes the supported behavior, validates the outcome, and can run again without a person clicking through dialogs.
Microsoft provides test codeunits, test runner codeunits, test pages, UI handlers, and assertion patterns for this purpose. Online production environments are not the place to execute automated tests; use sandboxes or container-based development environments according to Microsoft's documented limits.
Prefer calling the same public codeunit or document operation used by production behavior. Testing a private helper can be useful, but a suite made only of helper tests can stay green while permissions, events, posting behavior, or integration boundaries fail.
Use a clear arrange-act-assert structure:
// AL
codeunit 50120 "BA Order Tests"
{
Subtype = Test;
[Test]
[HandlerFunctions('ConfirmReleaseHandler')]
procedure ReleaseOrderRequiresConfirmation()
var
SalesHeader: Record "Sales Header";
ReleaseSalesDocument: Codeunit "Release Sales Document";
begin
CreateSalesOrder(SalesHeader);
ReleaseSalesDocument.Run(SalesHeader);
SalesHeader.TestField(Status, SalesHeader.Status::Released);
end;
[ConfirmHandler]
procedure ConfirmReleaseHandler(Question: Text[1024]; var Reply: Boolean)
begin
Reply := true;
end;
local procedure CreateSalesOrder(var SalesHeader: Record "Sales Header")
begin
// Use the project's shared test library to arrange a valid order.
end;
}
The example demonstrates the documented attributes and structure; the selected production codeunit's exact behavior can vary by version and setup, so compile and execute it against the target symbols during editorial review.
UI handlers replace messages, confirmations, menus, pages, reports, request pages, hyperlinks, notifications, and other interactions during an automated test. List each required handler in HandlerFunctions. Microsoft notes that a listed handler must be called; otherwise the test fails. That makes unexpected changes to the interaction visible instead of silently ignored.
A handler should verify the prompt or page state before returning a response. A confirmation handler that always replies true without checking the question can hide a new, unrelated confirmation.
Tests should leave the system in a known state and run in any order. Create records through shared test libraries, generate unique values when collisions matter, and avoid dependencies on a developer's existing company data. Use explicit work dates and setup values when the business result depends on them.
Do not make tests depend on live external services. Put an interface or queue boundary around integrations and test the AL behavior with a controlled implementation. Exercise the real external contract in a separate integration environment.
Positive tests prove that valid work succeeds. Negative tests prove that invalid work stops for the correct reason and leaves data correct. Microsoft documents AssertError for expected failures in test code. Validate meaningful error behavior, not an entire platform-generated string that can change harmlessly between versions.
Run a fast suite on pull requests and a broader suite for release candidates. Archive results with the compiled package. Recompile and rerun against Business Central preview artifacts so deprecated symbols and behavioral changes are found before the customer's update window.
A failed test is release evidence, not an inconvenience to rerun until it disappears. Record the defect, environmental cause, or reviewed expectation change.
Give every regression test a business reason in its name or surrounding documentation. When requirements change, reviewers can then decide whether the implementation regressed or the expected result needs an intentional update, with that decision preserved in source control.
Bitta Apps can add automated coverage to inherited extensions, build upgrade suites through AL development, and connect those gates to release-wave support and integration testing.