Skip to content

[test-improver] test: add edge case tests for UseConditionBaseWithTestClassAnalyzer (MSTEST0041)#9103

Merged
Evangelink merged 1 commit into
mainfrom
test-assist/useConditionBase-edge-cases-706f3df2ebd15a21
Jun 14, 2026
Merged

[test-improver] test: add edge case tests for UseConditionBaseWithTestClassAnalyzer (MSTEST0041)#9103
Evangelink merged 1 commit into
mainfrom
test-assist/useConditionBase-edge-cases-706f3df2ebd15a21

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Goal and Rationale

UseConditionBaseWithTestClassAnalyzer (MSTEST0041) flags classes that have a ConditionBaseAttribute subclass (e.g. [OSCondition], [CICondition], custom conditions) but are not marked as [TestClass]. Three code paths were untested:

  1. Multiple condition attributes on a non-test class — the analyzer uses FirstOrDefault, so only one diagnostic fires regardless of how many ConditionBase attributes are present. The message uses the first attribute's name.

  2. Abstract class without [TestClass] — unlike some other analyzers in this repo, UseConditionBaseWithTestClassAnalyzer has no abstract-class exemption. An abstract class with a condition attribute but no [TestClass] should trigger the diagnostic.

  3. Two-level derived condition attribute — the Inherits() check is recursive. An attribute that is a 2nd-level subclass of ConditionBaseAttribute should still trigger the diagnostic on a non-test class.

Approach

Added three new [TestMethod] test cases to UseConditionBaseWithTestClassAnalyzerTests.cs:

  • WhenNonTestClassHasMultipleConditionAttributes_SingleDiagnostic — verifies FirstOrDefault behavior: one diagnostic, named after the first attribute.
  • WhenAbstractNonTestClassHasConditionAttribute_Diagnostic — confirms no abstract exemption exists in this analyzer.
  • WhenTwoLevelDerivedConditionAttributeOnNonTestClass_Diagnostic — confirms Inherits() is recursive for condition attribute detection.

Test Status

Test run summary: Passed!
  total: 12
  failed: 0
  succeeded: 12
  skipped: 0
  duration: 7s 141ms

✅ All 12 tests pass (MSTest.Analyzers.UnitTests, net8.0, Debug — 9 original + 3 new).

Reproducibility

./build.sh --restore   # first run only
.dotnet/dotnet test test/UnitTests/MSTest.Analyzers.UnitTests/MSTest.Analyzers.UnitTests.csproj \
  -f net8.0 --no-build -c Debug \
  --filter "ClassName=MSTest.Analyzers.Test.UseConditionBaseWithTestClassAnalyzerTests"

Trade-offs

  • Tests exercise existing code paths only — no production changes, no maintenance burden beyond the tests.
  • Each test documents a specific invariant of the analyzer (FirstOrDefault behavior, no abstract guard, recursive Inherits check).

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Test Improver workflow. · 1K AIC · ⌖ 24.6 AIC · [◷]( · )

Add this agentic workflows to your repo

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/test-improver.md@main

…MSTEST0041)

Add three targeted unit tests that exercise untested code paths:

- WhenNonTestClassHasMultipleConditionAttributes_SingleDiagnostic: verifies
  FirstOrDefault behavior - only one diagnostic fires when a non-test class
  has two ConditionBase attributes (e.g. [OSCondition] + [CICondition]).
- WhenAbstractNonTestClassHasConditionAttribute_Diagnostic: confirms no
  abstract-class exemption exists; abstract classes without [TestClass] still
  trigger the diagnostic.
- WhenTwoLevelDerivedConditionAttributeOnNonTestClass_Diagnostic: confirms
  Inherits() is recursive - a 2nd-level ConditionBase subclass attribute on
  a non-test class still fires the diagnostic.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 13, 2026 23:36
@Evangelink Evangelink added type/automation Created or maintained by an agentic workflow. type/test-gap Missing or insufficient tests. labels Jun 13, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the MSTest analyzer unit tests for MSTEST0041 (UseConditionBaseWithTestClassAnalyzer) to cover previously untested analyzer behaviors, without modifying production analyzer logic.

Changes:

  • Added a test ensuring that multiple ConditionBaseAttribute-derived attributes on a non-test class produce a single diagnostic (matching the analyzer’s FirstOrDefault behavior).
  • Added a test confirming that an abstract non-test class with a condition attribute still triggers the diagnostic (no abstract exemption).
  • Added a test confirming the condition-attribute detection works for a two-level derived condition attribute (recursive Inherits()).
Show a summary per file
File Description
test/UnitTests/MSTest.Analyzers.UnitTests/UseConditionBaseWithTestClassAnalyzerTests.cs Adds three focused test cases covering multi-attribute, abstract-class, and two-level-inheritance scenarios for MSTEST0041.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 0

@Evangelink Evangelink marked this pull request as ready for review June 14, 2026 12:28
@Evangelink

Copy link
Copy Markdown
Member Author

🧪 Test quality grade — PR #9103

ΔTestGradeBandNotes
new UseConditionBaseWithTestClassAnalyzerTests.
WhenAbstractNonTestClassHasConditionAttribute_
Diagnostic
A 90–100 Comment explains the no-abstract-exemption edge case; asserts exact diagnostic location and attribute name.
new UseConditionBaseWithTestClassAnalyzerTests.
WhenNonTestClassHasMultipleConditionAttributes_
SingleDiagnostic
A 90–100 Comment documents the FirstOrDefault behavior; asserts single diagnostic with correct location and argument.
new UseConditionBaseWithTestClassAnalyzerTests.
WhenTwoLevelDerivedConditionAttributeOnNonTestClass_
Diagnostic
A 90–100 Comment explains the recursive inheritance check; longer code setup is justified by the 2-level attribute hierarchy.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Grade Tests on PR (on open / sync) workflow. · 159.9 AIC · ⌖ 12.8 AIC · [◷]( · )

@Evangelink Evangelink left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

🤖 Automated review by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

✅ 22/22 dimensions clean — no findings.

Context read:

  • src/Analyzers/MSTest.Analyzers/UseConditionBaseWithTestClassAnalyzer.cs — confirms FirstOrDefault behavior, no abstract-class guard, and that the Inherits() call traverses the full type hierarchy.
  • src/TestFramework/TestFramework/Attributes/TestMethod/ConditionBaseAttribute.cs — confirms GroupName and IsConditionMet are abstract, so Level2ConditionAttribute correctly inherits IsConditionMet => true from Level1ConditionAttribute and gets an implicit parameterless constructor that chains through Level1ConditionAttribute()ConditionBaseAttribute(ConditionMode.Include).

Per-test notes:

  • WhenNonTestClassHasMultipleConditionAttributes_SingleDiagnostic: GetAttributes() returns source-order attributes in Roslyn, so OSCondition (first in source) is correctly expected as the argument. The FirstOrDefault comment is accurate.
  • WhenAbstractNonTestClassHasConditionAttribute_Diagnostic: The analyzer performs no IsAbstract check, so the positive assertion is correct. The existing WhenTestClassHasOSConditionAttribute_NoDiagnostic covers the no-diagnostic path for the [TestClass] guard, making a separate abstract+TestClass complement unnecessary.
  • WhenTwoLevelDerivedConditionAttributeOnNonTestClass_Diagnostic: Level2ConditionAttribute is non-abstract (concrete IsConditionMet inherited from Level1ConditionAttribute), has a valid implicit parameterless constructor, and is a valid attribute target for [Level2Condition].

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Expert Code Review (on PR ready) workflow. · 409.2 AIC · ⌖ 12.4 AIC ·

@Evangelink Evangelink merged commit 3f25c6a into main Jun 14, 2026
57 checks passed
@Evangelink Evangelink deleted the test-assist/useConditionBase-edge-cases-706f3df2ebd15a21 branch June 14, 2026 19:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type/automation Created or maintained by an agentic workflow. type/test-gap Missing or insufficient tests.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants