Skip to main content

writing-tests

Decide where a test belongs and how to write it for this repository — ported xUnit tests against synthetic metadata, regression cases against the real shipped metadata, hostile-input and FsCheck property tests, reproducing a fuzzer crash, and running a single test. Use when adding or fixing any test under csharp/, when a test fails after a metadata sync, or when asked "where should this test go". Demo (bUnit) tests are covered by the changing-demo-ui skill instead.

Zur Installation springen

Quellinformationen

Repository
twcclegg/libphonenumber-csharp
Letzte Quellaktivität
17. September 2026 um 01:20
Erkannte Sprache von SKILL.md
Englisch
Sterne
922
Forks
157

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
writing-tests
description
Decide where a test belongs and how to write it for this repository — ported xUnit tests against synthetic metadata, regression cases against the real shipped metadata, hostile-input and FsCheck property tests, reproducing a fuzzer crash, and running a single test. Use when adding or fixing any test under csharp/, when a test fails after a metadata sync, or when asked "where should this test go". Demo (bUnit) tests are covered by the changing-demo-ui skill instead.
# Writing tests The suite runs against **two different metadata sets**, and putting a test in the wrong one makes it prove nothing. Decide that first. ## Which metadata does the test need? | You are… | Metadata | Where it goes | | --- | --- | --- | | Porting a Java test | Synthetic `PhoneNumberMetadataForTesting.xml` | The class mirroring the Java test file (`TestPhoneNumberUtil.cs`, `TestAsYouTypeFormatter.cs`, `TestPhoneNumberMatcher.cs`, `TestShortNumberInfo.cs`, …) | | Guarding a real number / region / crash | Real shipped metadata via `GetInstance()` | `TestPublicApiRobustness.cs` (curated inputs) or `TestPhoneNumberProperties.cs` (FsCheck) | | Asserting every region's example numbers still parse | Real | `TestExampleNumbers.cs` | | Testing a reader/writer of the binary format | Real | `TestBuildMetadataFromBin.cs`, `TestBuildPrefixMapFromBin.cs` | **Synthetic metadata** classes carry `[Collection("TestMetadataTestCase")]` and take `TestMetadataTestCase.PhoneUtil` — hand-built fake regions whose rules exist to exercise code paths. A real-world number parked there tells you nothing about how the library behaves for users. **Real metadata** classes call `PhoneNumberUtil.GetInstance()` (and the geocoder / carrier / time zone `GetInstance()`s). This is what ships and where the awkward regions live; an issue reported by a user is reproduced and guarded here. ## Regression and hostile-input cases `TestPublicApiRobustness.cs` drives each public entry point over an array of hostile strings inside a `[Fact]`, deliberately not `[Theory]`/`[MemberData]`: xunit serialises theory arguments for discovery and some inputs (lone surrogates, NUL) do not survive that. Add a new hostile input to the existing arrays, or a new `[Fact]` for a new entry point, asserting that the only exception that escapes is the documented one (`NumberParseException` for parsing). This pair of files has already caught an unbounded `stackalloc` and a `KeyNotFoundException` the well-formed-input suite missed. `TestPhoneNumberProperties.cs` is the FsCheck counterpart: `[Property(MaxTest = …)]` methods over generated input asserting invariants (`ValidNumbersRoundTripThroughE164`, `ValidNumbersAreAlsoPossible`, `NormalizeIsIdempotent`, `IsNumberMatchIsSymmetric`, …). **Keep the `using FsCheck;` / `using FsCheck.Xunit;` lines** even if a refactor stops needing them — the OSSF Scorecard fuzzing check greps for them and the score drops silently without. A crash from the weekly fuzzer (`fuzz.yml`, `csharp/PhoneNumbers.Fuzz/`) reproduces with `dotnet fuzz-out/PhoneNumbers.Fuzz.dll <crash-file>`; its README has the full recipe. Turn every finding into a `TestPublicApiRobustness` case so it stays fixed. ## After a metadata sync breaks a test A test that starts failing on a `metadata-update/*` PR is almost always right to fail: a region's example number or format changed upstream and the ported assertion is stale. Update the *test* to the new behaviour; never edit `resources/` to make it pass. If the failing test uses the synthetic metadata it cannot be the sync — look for a code change. ## Running ```bash dotnet test csharp/PhoneNumbers.Test --filter "FullyQualifiedName~TestPhoneNumberUtil.TestParseNationalNumber" dotnet test csharp/PhoneNumbers.Test --filter "FullyQualifiedName~TestPublicApiRobustness" dotnet test csharp/PhoneNumbers.slnx -p:TargetFrameworks=net10.0 # the PR check dotnet test csharp/PhoneNumbers.slnx # adds net8.0 ``` Tests never run on `netstandard2.0`; a broken fallback in `PhoneNumberUtil.netstandard.cs` only shows up in `dotnet build csharp`, so run that too when a change touches it. `csharp/coverlet.runsettings` excludes the generated `CountryCodeToRegionCodeMap` and the protobuf-style `*Builder` nested types from coverage; don't write tests whose only purpose is to lift the percentage on those. ## Conventions - Ported tests keep the Java test's name and order so the next port can diff against upstream. - New non-ported tests are named for the behaviour (`ParseFailsOnlyWithNumberParseException`), one concept per test, no snapshots. - Use the `RegionCode` constants in `csharp/PhoneNumbers.Test/RegionCode.cs` rather than typing region strings by hand.
Auf GitHub ansehen