AL Testing & Project Structure Rules
AL-Go workspace structure, test generation guidelines, and project organization rules
AL Testing & Project Structure Rules
These rules ensure proper project organization, test implementation, and workspace structure in AL-Go based development environments.
Rule 1: AL-Go Workspace Structure Guidelines
Intent
Establish clear separation between application code and test code in AL-Go workspace environments.
- App project contains Tables, Pages, Codeunits, Reports, APIs, Enums, etc.
- Test project contains Test Codeunits, Test Pages, Mock objects, Test data.
- Each project has its own app.json with appropriate dependencies.
- Test project references the App project as a dependency.
- Use App project ONLY for main application implementation, use Test project ONLY for test implementation, never include test files in the main App folder, and never include application logic in the Test folder.
- When working in AL-Go workspace, always place files in the correct project based on their purpose.
Examples
// Good example - Proper AL-Go workspace structure
Repository/
├── .AL-Go/
├── .github/
├── App/
│ ├── src/
│ │ ├── Setup/
│ │ ├── Feature1/
│ │ ├── Feature2/
│ │ ├── APIs/
│ ├── app.json
│ └── launch.json
├── Test/
│ ├── src/
│ │ ├── SetupTests/
│ │ ├── Feature1Tests/
│ │ ├── Feature2Tests/
│ │ ├── IntegrationTests/
│ ├── app.json
│ └── launch.json
└── al.code-workspace
Rule 2: Test Generation Guidelines
Intent
Control when and how test code is generated to maintain focus on main application implementation.
- DO NOT automatically generate test code unless explicitly requested
- Focus on main application implementation by default
- When user asks for implementation create only the main application objects
- Only generate test files when user specifically requests “Create tests for…”, “Generate unit tests…”, “Add test coverage…”, or “Write tests…”
- If tests are requested, place them in the Test project following the folder structure where test files should mirror the App project structure but in the Test project
- Unless the user explicitly requests tests, focus only on main application implementation
Rule 3: Project Dependencies Configuration
Intent
Establish correct dependency relationships between App and Test projects.
- App project app.json should NOT reference Test project
- Test project app.json MUST reference App project as dependency
- Test project should include testing frameworks (e.g., “Any”, “Library Assert”), and each project maintains its own dependencies.
- When configuring project dependencies, ensure Test project references App project but never the reverse and include appropriate testing frameworks in Test project.
Examples
// Good example - Test project app.json
{
"dependencies": [
{
"id": "your-app-id",
"name": "Your App Name",
"publisher": "Your Publisher",
"version": "1.0.0.0"
},
{
"id": "dd0be2ea-f733-4d65-bb34-a28f4624fb14",
"name": "Library Assert",
"publisher": "Microsoft",
"version": "20.0.0.0"
}
]
}
Rule 4: Unit Testing Best Practices
Intent
Write comprehensive unit tests that ensure reliability of business logic.
- Write unit tests for all business logic
- Follow given/when/then structure for test naming
- Use Assert statements for validating critical conditions
- Create test data factories for consistent test setup
- Always try to use standard library codeunits to create data and post documents
- When creating tests, use descriptive names that follow given/when/then pattern and include comprehensive assertions to validate expected behavior.
Examples
// Good example - Well-structured unit test with standard library codeunits
codeunit 50200 "Customer Management Tests"
{
Subtype = Test;
var
Assert: Codeunit Assert;
LibrarySales: Codeunit "Library - Sales";
LibraryInventory: Codeunit "Library - Inventory";
LibraryRandom: Codeunit "Library - Random";
LibraryERM: Codeunit "Library - ERM";
[Test]
procedure GivenValidCustomer_WhenCreatingCustomer_ThenCustomerIsCreated()
var
Customer: Record Customer;
CustomerManagement: Codeunit "Customer Management";
CustomerNo: Code[20];
begin
// Given - Valid customer data using library
LibrarySales.CreateCustomer(Customer);
Customer."Credit Limit (LCY)" := LibraryRandom.RandDec(10000, 2);
// When - Creating customer
CustomerNo := CustomerManagement.CreateCustomer(Customer);
// Then - Customer is created successfully
Assert.IsTrue(Customer.Get(CustomerNo), 'Customer should be created');
Assert.AreEqual(Customer.Name, Customer.Name, 'Customer name should match');
end;
[Test]
procedure GivenSalesOrder_WhenPostingOrder_ThenInvoiceIsCreated()
var
SalesHeader: Record "Sales Header";
SalesLine: Record "Sales Line";
Item: Record Item;
PostedInvoiceNo: Code[20];
begin
// Given - Sales order with library-created data
LibraryInventory.CreateItem(Item);
LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, '');
LibrarySales.CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::Item, Item."No.", LibraryRandom.RandInt(10));
// When - Posting sales order
PostedInvoiceNo := LibrarySales.PostSalesDocument(SalesHeader, true, true);
// Then - Posted invoice exists
Assert.AreNotEqual('', PostedInvoiceNo, 'Posted invoice should be created');
end;
}
Rule 5: Feature-Based Test Organization
Intent
Organize test files to mirror the application structure while maintaining clear separation.
- Test files should mirror App project structure in Test project
- Use same feature-based organization for tests
- Place shared test utilities in Common folder
- Maintain consistent naming patterns
Examples
// Good example - Mirrored test structure
App/src/
├── NoSeries/
│ ├── NoSeries.Table.al
│ └── NoSeries.Page.al
└── Sales/
└── Invoice/
└── SalesInvoice.Page.al
Test/src/
├── NoSeries/
│ └── NoSeriesTests.Codeunit.al
├── Sales/
│ └── Invoice/
│ └── SalesInvoiceTests.Codeunit.al
└── Common/
└── TestHelpers/
└── TestDataFactory.Codeunit.al
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.
Last modified August 11, 2025: Merge pull request #264 from microsoft/jeremy-siteops (f82dfd0)
by Jeremy Vyska