mirror of
https://github.com/microsoft/BCQuality.git
synced 2026-10-05 14:46:55 +01:00
Improve partner onboarding and documentation navigation
Lead with a complete plugin quick start and add task-oriented usage, troubleshooting, customization, and contribution guides. Preserve the broader plugin framing, correct conflicting contract guidance, support Agents folder reviews, and align repository validation. Convert existing sample references to clickable links without changing knowledge rules. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
a21edfec46
commit
b6da405376
276 changed files with 1287 additions and 756 deletions
|
|
@ -17,10 +17,10 @@ application-area: [all]
|
|||
|
||||
Follow every `asserterror` with a verification of the error it expects, and prefer the reusable `Library Assert` helpers over hardcoded literals. For a mandatory-field check, `Assert.ExpectedTestFieldError(FieldCaption, ExpectedValue)` encapsulates both the message and the `TestField` code, so the test survives caption or code changes and does not repeat that knowledge in every method. For other errors, pair `Assert.ExpectedError` with a stable substring — ideally a shared `Label`, not an inline sentence — and, where known, `Assert.ExpectedErrorCode`. When a needed check is missing from the shared library, extend `Library Assert` (or your own assert library) with a helper rather than hardcoding message text and codes across tests; matching on a code or an invariant fragment keeps the test from going blind to the wrong error when a caption is localized.
|
||||
|
||||
See sample: `asserterror-needs-expectederror-and-code.good.al`.
|
||||
See sample: [`asserterror-needs-expectederror-and-code.good.al`](asserterror-needs-expectederror-and-code.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
`asserterror DoInvalid();` with nothing after it. The test asserts only that the call failed somehow; swap the validation for a different bug and the test still passes, certifying a guard that may no longer fire. A negative test that cannot tell one error from another verifies almost nothing.
|
||||
|
||||
See sample: `asserterror-needs-expectederror-and-code.bad.al`.
|
||||
See sample: [`asserterror-needs-expectederror-and-code.bad.al`](asserterror-needs-expectederror-and-code.bad.al).
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ What matters is the effective permission context at the moment the protected ope
|
|||
|
||||
Use `TestPermissions::Restrictive` for a permission-sensitive test and lower the current test user with the test framework's `"Permissions Mock"` or `"Library - Lower Permissions"` before invoking the protected operation. Assign a permission context that actually contains the rights the scenario tests — either the permission set itself or a role that includes it — and restore or stop the mock afterward. Use `Disabled` only for suites that do not assert permission behavior, or where the test lowers the context explicitly through the test libraries instead of relying on the runner. Do not require a test to apply the permission set under test directly when it reaches the same rights through a composed role and then asserts the boundary.
|
||||
|
||||
See sample: `permission-tests-must-lower-the-execution-context.good.al`.
|
||||
See sample: [`permission-tests-must-lower-the-execution-context.good.al`](permission-tests-must-lower-the-execution-context.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Setting `TestPermissions = Disabled` or leaving the effective D365 Full Access context in place while asserting that a limited user is denied, or adding a `[TestPermissions(...)]` attribute without any runner/test-library code that applies the intended permission set. Do not report the mirror image: a test that lowers the context through a role including the permission set under test, and then asserts the boundary, has exercised that permission set and is not a coverage gap.
|
||||
|
||||
See sample: `permission-tests-must-lower-the-execution-context.bad.al`.
|
||||
See sample: [`permission-tests-must-lower-the-execution-context.bad.al`](permission-tests-must-lower-the-execution-context.bad.al).
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ application-area: [all]
|
|||
|
||||
Run independent suites with `TestIsolation = Codeunit` or `Function`, choosing the narrowest boundary the runner supports. Pair this with the appropriate method-level `TransactionModel`: `AutoCommit` permits code under test to commit, while runner isolation still restores the database afterward. Keep isolation disabled only for an intentionally shared-state suite whose ordering and cleanup are explicit.
|
||||
|
||||
See sample: `testisolation-belongs-on-the-test-runner.good.al`.
|
||||
See sample: [`testisolation-belongs-on-the-test-runner.good.al`](testisolation-belongs-on-the-test-runner.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
An `AutoCommit` test exercises committed writes under a test runner that omits `TestIsolation` or sets it to `Disabled`, then assumes the database is restored automatically. This article owns runner-level rollback; `transactionmodel-attribute-governs-test-transactions.md` separately owns the method attribute.
|
||||
|
||||
See sample: `testisolation-belongs-on-the-test-runner.bad.al`.
|
||||
See sample: [`testisolation-belongs-on-the-test-runner.bad.al`](testisolation-belongs-on-the-test-runner.bad.al).
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ application-area: [all]
|
|||
|
||||
Default to `AutoRollback`: it opens a write transaction at the start of the test, runs the test body, and rolls back at the end, leaving the database in its original state. Pick `AutoCommit` only when the code under test genuinely calls `Commit` — posting routines, job-queue handlers, integration flows — and make the test exercise that commit path. Pair the test codeunit with a `TestIsolation`-enabled test runner so committed changes are reverted at a higher scope. Pick `None` only for read-only tests or tests that drive UI code without writing from the test method itself.
|
||||
|
||||
See sample: `transactionmodel-attribute-governs-test-transactions.good.al`.
|
||||
See sample: [`transactionmodel-attribute-governs-test-transactions.good.al`](transactionmodel-attribute-governs-test-transactions.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Applying `AutoRollback` to every test method without checking whether the tested business logic calls `Commit`. The test throws at the first Commit, leaving no verdict on the behavior it intended to verify; in a CI run this looks like a flake or a setup bug, not a specification mismatch. The mirror-image anti-pattern is defaulting to `AutoCommit` across the suite "to avoid the error" — without a `TestIsolation` runner this permanently dirties the test database between runs and produces order-dependent test outcomes.
|
||||
|
||||
See sample: `transactionmodel-attribute-governs-test-transactions.bad.al`.
|
||||
See sample: [`transactionmodel-attribute-governs-test-transactions.bad.al`](transactionmodel-attribute-governs-test-transactions.bad.al).
|
||||
|
|
|
|||
|
|
@ -21,10 +21,10 @@ Beyond that wiring guarantee, the test must verify the behavior it cares about.
|
|||
|
||||
List the handlers the scenario triggers, keep an optional notification handler listed for a notification the scenario may conditionally raise, and make each executed handler contribute meaningful evidence. For a single modal page, reset a capture variable before the action, capture a concrete value from the page in the handler, and assert the expected value after `RunModal`. For ordered or repeated interactions, let the test enqueue expectations, let handlers dequeue and verify them, clear storage during initialization, and finish with `AssertEmpty`.
|
||||
|
||||
See sample: `ui-handlers-in-tests.good.al`.
|
||||
See sample: [`ui-handlers-in-tests.good.al`](ui-handlers-in-tests.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Omitting a handler for a UI call, listing a nonoptional handler the path never reaches, or claiming action success from a Boolean set before the action runs. A handler that only closes a page can also leave the test without a semantic assertion. Do not flag the absence of queue storage by itself; require it only when the test needs to prove interaction order, count, text, replies, or a scripted sequence. Do not flag a listed `[SendNotificationHandler(true)]` or `[RecallNotificationHandler(true)]` that the run does not reach, and never propose removing one: the entry is what keeps the test passing on the runs where the notification does fire.
|
||||
|
||||
See sample: `ui-handlers-in-tests.bad.al`.
|
||||
See sample: [`ui-handlers-in-tests.bad.al`](ui-handlers-in-tests.bad.al).
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ BC ships a layer of test Library codeunits — `LibrarySales`, `LibraryPurchase`
|
|||
|
||||
Reach for the matching Library codeunit before writing manual record setup: `LibrarySales.CreateCustomer`, `LibrarySales.CreateSalesHeader`/`CreateSalesLine`, `LibraryInventory.CreateItem`, `LibraryERM.CreateGLAccount`, and `LibraryRandom.RandInt`/`RandDec` for values. Create the prerequisite parents first and reference their primary keys from dependent records, and `Validate` the foreign-key field so the `TableRelation` — and any field-validation logic — runs exactly as it would in production. Pass the records they return into the code under test. The fixtures stay valid across upgrades because the library — not your test — owns the knowledge of what a well-formed record requires.
|
||||
|
||||
See sample: `use-library-codeunits-for-test-fixtures.good.al`.
|
||||
See sample: [`use-library-codeunits-for-test-fixtures.good.al`](use-library-codeunits-for-test-fixtures.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
`Customer.Init(); Customer."No." := 'X'; Customer.Insert();` — a record with a hand-picked primary key, no number-series entry, and none of the mandatory fields a real customer needs. It compiles and may even insert, but it bypasses setup the production code assumes, and it breaks the first time the schema gains a required field the test does not know about.
|
||||
|
||||
See sample: `use-library-codeunits-for-test-fixtures.bad.al`.
|
||||
See sample: [`use-library-codeunits-for-test-fixtures.bad.al`](use-library-codeunits-for-test-fixtures.bad.al).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue