You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
MSTest is in the middle of a large collection-assertion modernization wave: 136 new Assert.* Span/Memory overloads are staged in PublicAPI.Unshipped.txt, covering AreSequenceEqual, ContainsAll, AreAllDistinct, AreAllOfType, Contains, DoesNotContain, IsEmpty, IsNotEmpty, and more. The MSTEST0068 analyzer (CollectionAssertToAssert) was introduced to guide users from the legacy CollectionAssert class toward this modern API.
However, two CollectionAssert methods β IsSubsetOf and IsNotSubsetOf β have no counterpart in the modern Assert class, and the MSTEST0068 analyzer silently skips them (returns without a diagnostic). Users who call CollectionAssert.IsSubsetOf today receive no guidance, and are left relying on the legacy API indefinitely. Additionally, CollectionAssert.AreEquivalent and CollectionAssert.AreNotEquivalent overloads that accept an IComparer are also excluded from the analyzer migration path because the Assert.AreEquivalent/AreNotEquivalent methods use generic IEqualityComparer<T> rather than the non-generic IComparer.
Addressing these gaps will complete the CollectionAssert-to-Assert migration story and give users a fully modern, type-safe subset-testing API.
CollectionAssert methods with NO Assert equivalent
2 (IsSubsetOf, IsNotSubsetOf)
β Gap
CollectionAssert overloads skipped due to comparer mismatch
4 (AreEquivalent + IComparer, AreNotEquivalent + IComparer, same generic variants)
β οΈ Gap
MSTEST0068 diagnostic on IsSubsetOf calls
0 (silently skipped)
β No guidance
Findings
Strengths
The new Assert collection methods (AreSequenceEqual, ContainsAll, AreAllDistinct, etc.) have comprehensive IEnumerable(T) AND Span/Memory overloads, giving users full flexibility.
Failure messages for the new assertions are detailed and structured (missing elements, null indices, mismatch positions surfaced).
The MSTEST0068 analyzer covers 9 of the 11 distinct CollectionAssert method names.
Areas for Improvement
β οΈ HIGH β Assert.IsSubsetOf and Assert.IsNotSubsetOf methods do not exist.CollectionAssert.IsSubsetOf verifies that every element of a subset collection appears in a superset. There is currently no Assert.IsSubsetOf(IEnumerable<T> subset, IEnumerable<T> superset) equivalent in the modern API. Users cannot migrate even if they want to.
β οΈ HIGH β MSTEST0068 silently skips IsSubsetOf / IsNotSubsetOf. When the analyzer encounters CollectionAssert.IsSubsetOf(...) or CollectionAssert.IsNotSubsetOf(...), the switch expression returns null and the method returns immediately β no diagnostic, no migration hint. The user sees nothing.
β οΈ MEDIUM β CollectionAssert.AreEquivalent(ICollection, ICollection, IComparer) has no Assert migration path. The condition !HasIComparerParameter(targetMethod) in CollectionAssertToAssertAnalyzer.cs:90 gates out the IComparer-bearing overloads of AreEquivalent/AreNotEquivalent. The modern Assert.AreEquivalent<T> uses IEqualityComparer<T>, not IComparer. Adding an IEqualityComparer-based migration note for these calls would help close the gap.
β οΈ LOW β No SequenceOrder.InAnyOrder shorthand for AreSequenceEqual. The analyzer maps CollectionAssert.AreEquivalent (order-insensitive) to Assert.AreSequenceEqual(..., SequenceOrder.InAnyOrder). This is correct but verbose. A future Assert.AreEquivalentSequence or accepting SequenceOrder directly at the call level (already exists) is adequate β but documentation could clarify this path for migrators.
π€ Suggested Improvement Tasks
The following actionable tasks address the findings above.
Task 1: Add Assert.IsSubsetOf and Assert.IsNotSubsetOf methods
Priority: High Estimated Effort: Small
Add Assert.IsSubsetOf<T>(IEnumerable<T>? subset, IEnumerable<T>? superset, ...) and the corresponding IsNotSubsetOf overload to the Assert class in src/TestFramework/TestFramework/Assertions/, mirroring the IEnumerable<T> and non-generic IEnumerable patterns established by ContainsAll and AreAllDistinct. Include Span/Memory variants for consistency with the current wave of additions. Add entries to PublicAPI.Unshipped.txt (both net/ and base).
The argument order matches (subset first, superset second), so a FixKindSwapTwoArgs variant or a new simple fix kind should work. Add a corresponding code fixer entry in CollectionAssertToAssertFixer.cs and unit tests in MSTest.Analyzers.UnitTests.
Task 3: Provide migration guidance for CollectionAssert.AreEquivalent(IComparer) overloads
Priority: Medium Estimated Effort: Small
Currently, CollectionAssert.AreEquivalent(expected, actual, comparer) is silently skipped by MSTEST0068 because the IComparer non-generic parameter has no direct Assert.AreEquivalent<T>(IEqualityComparer<T>) equivalent. Two options:
Option A (Recommended): Surface a diagnostic with an informational message saying the call cannot be auto-migrated because Assert.AreEquivalent<T> requires a generic IEqualityComparer<T> β guiding the user to refactor manually. This is better than silent skipping.
Option B: If feasible, add CollectionAssert.AreEquivalent(ICollection, ICollection, IEqualityComparer) and wire up the migration automatically.
Task 4: Audit and document unmigrated CollectionAssert patterns in docs/migration guide
Priority: Medium Estimated Effort: Small
Update the migration documentation (e.g., the CollectionAssertToAssert analyzer docs or the MSTest migration guide) to explicitly list which CollectionAssert methods:
Have a one-to-one Assert equivalent and are auto-migrated by MSTEST0068
Have a semantic equivalent but require manual argument or type changes
Currently have no Assert equivalent (until Task 1 lands)
This prevents user confusion when MSTEST0068 fires on some calls but not others in the same test file.
Relevant files:
docs/ or wiki (if docs live externally)
src/Analyzers/MSTest.Analyzers/CollectionAssertToAssertAnalyzer.cs β XML doc for the diagnostic
Task 5: Add IEnumerable<T> overloads with IEqualityComparer<T> for ContainsSingle
Priority: Low Estimated Effort: Small
The Assert.ContainsSingle method has IEnumerable<T> and predicate-based overloads but no IEqualityComparer<T> overload for the value-based form. All other comparison-based collection assertions (Contains, ContainsAll, DoesNotContain, AreAllDistinct) accept a comparer. Adding ContainsSingle<T>(T expected, IEnumerable<T> collection, IEqualityComparer<T> comparer, ...) would complete the pattern.
Add Assert.IsSubsetOf / Assert.IsNotSubsetOf β Priority: High. These are the only two CollectionAssert methods that have no modern Assert equivalent, breaking the migration story. The implementation is straightforward given the existing ContainsAll pattern.
Wire MSTEST0068 for IsSubsetOf/IsNotSubsetOf β Priority: High. Once the Assert methods exist, the analyzer changes are a 2-line switch entry and a fixer registration.
Short-term Actions (This Month)
Address IComparer-bearing AreEquivalent overloads β Priority: Medium. At minimum, surface an informational diagnostic instead of silently returning, so users understand why that specific call isn't being flagged.
Add ContainsSingle with comparer β Priority: Low. Completes the comparer consistency pattern across all value-based collection assertions.
Next analysis: 2026-07-23 β Focus area selected based on diversity algorithm
Warning
Firewall blocked 1 domain
The following domain was blocked by the firewall during workflow execution:
awmgmcpg
To allow these domains, add them to the network.allowed list in your workflow frontmatter:
π― Repository Quality Improvement Report β Collection Assertion API Completeness
Analysis Date: 2026-07-22
Focus Area: collection-assertion-api-completeness
Strategy Type: Custom
Executive Summary
MSTest is in the middle of a large collection-assertion modernization wave: 136 new
Assert.*Span/Memory overloads are staged inPublicAPI.Unshipped.txt, coveringAreSequenceEqual,ContainsAll,AreAllDistinct,AreAllOfType,Contains,DoesNotContain,IsEmpty,IsNotEmpty, and more. TheMSTEST0068analyzer (CollectionAssertToAssert) was introduced to guide users from the legacyCollectionAssertclass toward this modern API.However, two
CollectionAssertmethods βIsSubsetOfandIsNotSubsetOfβ have no counterpart in the modernAssertclass, and theMSTEST0068analyzer silently skips them (returns without a diagnostic). Users who callCollectionAssert.IsSubsetOftoday receive no guidance, and are left relying on the legacy API indefinitely. Additionally,CollectionAssert.AreEquivalentandCollectionAssert.AreNotEquivalentoverloads that accept anIComparerare also excluded from the analyzer migration path because theAssert.AreEquivalent/AreNotEquivalentmethods use genericIEqualityComparer<T>rather than the non-genericIComparer.Addressing these gaps will complete the
CollectionAssert-to-Assertmigration story and give users a fully modern, type-safe subset-testing API.Full Analysis Report
Focus Area: Collection Assertion API Completeness
Current State Assessment
Metrics Collected:
Findings
Strengths
MSTEST0068analyzer covers 9 of the 11 distinctCollectionAssertmethod names.Areas for Improvement
Assert.IsSubsetOfandAssert.IsNotSubsetOfmethods do not exist.CollectionAssert.IsSubsetOfverifies that every element of asubsetcollection appears in asuperset. There is currently noAssert.IsSubsetOf(IEnumerable<T> subset, IEnumerable<T> superset)equivalent in the modern API. Users cannot migrate even if they want to.IsSubsetOf/IsNotSubsetOf. When the analyzer encountersCollectionAssert.IsSubsetOf(...)orCollectionAssert.IsNotSubsetOf(...), the switch expression returnsnulland the method returns immediately β no diagnostic, no migration hint. The user sees nothing.CollectionAssert.AreEquivalent(ICollection, ICollection, IComparer)has noAssertmigration path. The condition!HasIComparerParameter(targetMethod)inCollectionAssertToAssertAnalyzer.cs:90gates out theIComparer-bearing overloads ofAreEquivalent/AreNotEquivalent. The modernAssert.AreEquivalent<T>usesIEqualityComparer<T>, notIComparer. Adding anIEqualityComparer-based migration note for these calls would help close the gap.SequenceOrder.InAnyOrdershorthand forAreSequenceEqual. The analyzer mapsCollectionAssert.AreEquivalent(order-insensitive) toAssert.AreSequenceEqual(..., SequenceOrder.InAnyOrder). This is correct but verbose. A futureAssert.AreEquivalentSequenceor acceptingSequenceOrderdirectly at the call level (already exists) is adequate β but documentation could clarify this path for migrators.π€ Suggested Improvement Tasks
The following actionable tasks address the findings above.
Task 1: Add
Assert.IsSubsetOfandAssert.IsNotSubsetOfmethodsPriority: High
Estimated Effort: Small
Add
Assert.IsSubsetOf<T>(IEnumerable<T>? subset, IEnumerable<T>? superset, ...)and the correspondingIsNotSubsetOfoverload to theAssertclass insrc/TestFramework/TestFramework/Assertions/, mirroring theIEnumerable<T>and non-genericIEnumerablepatterns established byContainsAllandAreAllDistinct. Include Span/Memory variants for consistency with the current wave of additions. Add entries toPublicAPI.Unshipped.txt(bothnet/and base).Relevant files:
src/TestFramework/TestFramework/Assertions/β addAssert.IsSubsetOf.cssrc/TestFramework/TestFramework/PublicAPI/PublicAPI.Unshipped.txtsrc/TestFramework/TestFramework/PublicAPI/net/PublicAPI.Unshipped.txttest/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.IsSubsetOf.cs(new)Task 2: Add
IsSubsetOf/IsNotSubsetOfmappings toMSTEST0068(CollectionAssertToAssert)Priority: High
Estimated Effort: Small
Once
Assert.IsSubsetOfexists (Task 1), extend the switch inCollectionAssertToAssertAnalyzer.csto map:CollectionAssert.IsSubsetOf(subset, superset)βAssert.IsSubsetOf(subset, superset)CollectionAssert.IsNotSubsetOf(subset, superset)βAssert.IsNotSubsetOf(subset, superset)The argument order matches (subset first, superset second), so a
FixKindSwapTwoArgsvariant or a new simple fix kind should work. Add a corresponding code fixer entry inCollectionAssertToAssertFixer.csand unit tests inMSTest.Analyzers.UnitTests.Relevant files:
src/Analyzers/MSTest.Analyzers/CollectionAssertToAssertAnalyzer.cssrc/Analyzers/MSTest.Analyzers.CodeFixes/CollectionAssertToAssertFixer.cstest/UnitTests/MSTest.Analyzers.UnitTests/CollectionAssertToAssertAnalyzerTests.csTask 3: Provide migration guidance for
CollectionAssert.AreEquivalent(IComparer)overloadsPriority: Medium
Estimated Effort: Small
Currently,
CollectionAssert.AreEquivalent(expected, actual, comparer)is silently skipped by MSTEST0068 because theIComparernon-generic parameter has no directAssert.AreEquivalent<T>(IEqualityComparer<T>)equivalent. Two options:Assert.AreEquivalent<T>requires a genericIEqualityComparer<T>β guiding the user to refactor manually. This is better than silent skipping.CollectionAssert.AreEquivalent(ICollection, ICollection, IEqualityComparer)and wire up the migration automatically.Relevant files:
src/Analyzers/MSTest.Analyzers/CollectionAssertToAssertAnalyzer.cs(lines 90β91)Task 4: Audit and document unmigrated
CollectionAssertpatterns in docs/migration guidePriority: Medium
Estimated Effort: Small
Update the migration documentation (e.g., the
CollectionAssertToAssertanalyzer docs or the MSTest migration guide) to explicitly list whichCollectionAssertmethods:Assertequivalent and are auto-migrated by MSTEST0068Assertequivalent (until Task 1 lands)This prevents user confusion when MSTEST0068 fires on some calls but not others in the same test file.
Relevant files:
docs/or wiki (if docs live externally)src/Analyzers/MSTest.Analyzers/CollectionAssertToAssertAnalyzer.csβ XML doc for the diagnosticTask 5: Add
IEnumerable<T>overloads withIEqualityComparer<T>forContainsSinglePriority: Low
Estimated Effort: Small
The
Assert.ContainsSinglemethod hasIEnumerable<T>and predicate-based overloads but noIEqualityComparer<T>overload for the value-based form. All other comparison-based collection assertions (Contains,ContainsAll,DoesNotContain,AreAllDistinct) accept a comparer. AddingContainsSingle<T>(T expected, IEnumerable<T> collection, IEqualityComparer<T> comparer, ...)would complete the pattern.Relevant files:
src/TestFramework/TestFramework/Assertions/Assert.ContainsSingle.cssrc/TestFramework/TestFramework/PublicAPI/PublicAPI.Unshipped.txtπ Historical Context
Previous Focus Areas
π― Recommendations
Immediate Actions (This Week)
Add
Assert.IsSubsetOf/Assert.IsNotSubsetOfβ Priority: High. These are the only twoCollectionAssertmethods that have no modernAssertequivalent, breaking the migration story. The implementation is straightforward given the existingContainsAllpattern.Wire MSTEST0068 for
IsSubsetOf/IsNotSubsetOfβ Priority: High. Once the Assert methods exist, the analyzer changes are a 2-line switch entry and a fixer registration.Short-term Actions (This Month)
IComparer-bearingAreEquivalentoverloads β Priority: Medium. At minimum, surface an informational diagnostic instead of silently returning, so users understand why that specific call isn't being flagged.ContainsSinglewith comparer β Priority: Low. Completes the comparer consistency pattern across all value-based collection assertions.Next analysis: 2026-07-23 β Focus area selected based on diversity algorithm
Warning
Firewall blocked 1 domain
The following domain was blocked by the firewall during workflow execution:
awmgmcpgSee Network Configuration for more information.
Add this agentic workflow to your repo
To install this agentic workflow, run