mirror of
https://github.com/microsoft/BCQuality.git
synced 2026-10-07 15:46:55 +01:00
Address review: TableRelation validation carve-out, RecordRef nits
- tablerelation: fields with ValidateTableRelation/TestTableRelation = false are skipped by codeunit 134926 and may be longer (filter/totaling fields); shorter is still a finding. Add Code/Text type rule, BaseApp evidence, a ValidateTableRelation = false filter field to the good fixture, and the carve-out to the data-modeling cue. - recordref: add FindLast/Next, relabel SplitLocalTableFilter as filter splitting, mark fixtures as test-library-style helpers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
260d064ece
commit
01967ff808
8 changed files with 33 additions and 14 deletions
|
|
@ -60,7 +60,7 @@ The following targeted checks cover every current `testing` article. Treat each
|
|||
- A shared/lazy `Initialize()`-style fixture helper creates fixture data without a following `Commit()`, in a test method whose body later forces its own rollback (for example `asserterror Error(...)` used for end-of-test cleanup) — `commit-shared-test-fixture-inside-lazy-initialize`. The presence of `Commit()` after the fixture is the compliant shape, not the signal to look for; the missing-`Commit()` shape combined with a later deliberate rollback is the anti-pattern. Require runner/repository context for the `TestIsolation` value: a standalone test file cannot prove which runner executes it, and under `Function`-level isolation this whole pattern is moot regardless of `Commit()` — do not raise the finding when the executing runner's `TestIsolation` is known to be `Function`.
|
||||
- Changed code subscribes to `OnAfterRemoveTableRelation`, calls `RemoveTableRelation`, or references `Codeunit "Table Relation Test"`/134926 — `table-relation-test-exclude-known-invalid-relations-via-event`.
|
||||
- Test fixture code assigns a hardcoded literal to a primary-key field or a field the test relies on as a unique lookup identifier, hand-builds a "unique" value for such a field (string concatenation, a counter, `Format(CurrentDateTime)`), or truncates `LibraryUtility.GenerateGUID()`'s result with `CopyStr` for such a field shorter than 10 characters — `use-generateguid-for-unique-test-fixture-values`. Calling `GenerateGUID()` untruncated into a full-length field, `GenerateRandomCodeWithLength` for a shorter field needing real verified uniqueness, or `GenerateRandomCode20` specifically for a `Code[20]` field, is the compliant shape, not the signal to flag. `GenerateRandomCode20` is not a substitute for `GenerateRandomCodeWithLength` on a shorter field — it truncates `GenerateGUID()`'s sequential value down to the field's length by keeping the *leftmost* characters, which change the slowest, so retries against a short field can churn through the same truncated prefix far longer than `GenerateRandomCodeWithLength`'s equivalent. A hardcoded or deterministic value in an ordinary descriptive field is not this anti-pattern — that field carries no uniqueness constraint. Do not claim `GenerateRandomCode` (without `WithLength`/`20`) or `GenerateRandomXMLText` verify uniqueness against the real table, or that `GenerateRandomCode` is collision-free even within one test run for a short field — none of that is true.
|
||||
- Changed code calls `RecordRef.Open(<table>, true[, ...])` with a literal `true` and then, on that same `RecordRef` with no `Insert` into it, uses `IsEmpty`, `Find`, `FindFirst`, `FindSet`, `Get`, or `Count` to decide whether a value already exists in the table (typically a generate-until-unused loop ending `until RecRef.IsEmpty()`) — `recordref-open-temp-parameter-defeats-real-table-checks`. A temporary open used only as a validation sandbox (`Insert` then `Validate`), to parse a view via `SetView`/`GetFilter`, or to read metadata such as `SystemIdNo` is not this anti-pattern; neither is a non-literal `Temp` argument. A call to `LibraryUtility.GenerateRandomCode` itself is owned by `use-generateguid-for-unique-test-fixture-values`, not this cue.
|
||||
- Changed code calls `RecordRef.Open(<table>, true[, ...])` with a literal `true` and then, on that same `RecordRef` with no `Insert` into it, uses `IsEmpty`, `Find`, `FindFirst`, `FindLast`, `FindSet`, `Next`, `Get`, or `Count` to decide whether a value already exists in the table (typically a generate-until-unused loop ending `until RecRef.IsEmpty()`) — `recordref-open-temp-parameter-defeats-real-table-checks`. A temporary open used only as a validation sandbox (`Insert` then `Validate`), to parse a view via `SetView`/`GetFilter`, or to read metadata such as `SystemIdNo` is not this anti-pattern; neither is a non-literal `Temp` argument. A call to `LibraryUtility.GenerateRandomCode` itself is owned by `use-generateguid-for-unique-test-fixture-values`, not this cue.
|
||||
- A test asserts against a `TestPage` field's `.Visible()` or `.Enabled()` — `use-testpage-visible-enabled-to-verify-field-ui-state`. When the assertion is against `.Editable()`, or the page is opened with `OpenEdit()` specifically to check editability — `use-testpage-editable-to-verify-field-editability`.
|
||||
- A test path raises UI and `[HandlerFunctions(...)]` does not match the invoked handlers, or the test has no meaningful evidence of the UI result (for example, it treats a Boolean set before the action as proof of success) — `ui-handlers-in-tests`. A capture/reset/assert-after-`RunModal` pattern is valid. Enqueue/dequeue and `AssertEmpty` are required only when order, count, text, replies, or a scripted sequence is part of the contract. Only nonoptional handlers have to execute: a listed handler declared `[SendNotificationHandler(true)]` or `[RecallNotificationHandler(true)]` is optional by design, so do not treat it as unmatched when the run never raises the notification.
|
||||
- A test's `[GIVEN]`/setup looks up a hardcoded code/number/name assumed to already exist instead of creating it, leaves a mandatory field on a created record empty, uses a value that doesn't satisfy the scenario's own explicit length/format requirement (for example a truncation test whose value never exceeds the field), or a scenario-defining value (amount, quantity, percentage, date, threshold, rounding precision) is generated/randomized instead of an explicit chosen value — `test-data-must-be-random-and-complete`. Generating incidental fixture values (identifiers, names, descriptions) via the standard library codeunits is the compliant shape, not the signal to flag, and neither is a short-but-valid value in an otherwise-unremarkable field.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue