Skip to content

Limit Mock.Verify() recursion to framework-created inner mocks - #1708

Merged
kzu merged 4 commits into
mainfrom
copilot/fix-mock-invocation-issue
Sep 24, 2026
Merged

kzu merged 4 commits into
mainfrom
copilot/fix-mock-invocation-issue

Conversation

Copilot AI commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Mock.Verify() currently walks into any mock returned by a setup, so verifying one mock can fail on unmet verifiable setups configured on a different mock. This shows up when using explicit .Returns(otherMock.Object) and verifying mocks in separate phases.

  • Behavioral fix: scope recursive verification

    • Updated verification traversal in Mock.Verify to recurse only through InnerMockSetup (i.e., Moq-created object-graph links), instead of recursing through all setups.
    • This preserves recursive verification for true inner-mock chains while preventing cross-mock leakage for explicitly returned mocks.
  • Regression coverage: issue scenario

    • Added Issue1699 regression test in IssueReportsFixture that reproduces:
      • mockOne.Setup(...).Returns(mockTwo.Object).Verifiable();
      • mockTwo.Setup(...).Verifiable();
      • mockOne.Verify() should succeed before mockTwo interactions occur.
  • Example of the affected pattern

    mockOne.Setup(x => x.GetSomething()).Returns(mockTwo.Object).Verifiable();
    mockTwo.Setup(x => x.DoSomething()).Verifiable();
    
    objectToTest.FirstMethod();
    mockOne.Verify();   // should verify only mockOne expectations
    
    objectToTest.SecondMethod();
    mockTwo.Verify();

Co-authored-by: kzu <169707+kzu@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix missing invocations error on mock verification Limit Mock.Verify() recursion to framework-created inner mocks Sep 24, 2026
Copilot AI requested a review from kzu September 24, 2026 16:03
@kzu
kzu marked this pull request as ready for review September 24, 2026 17:21
@kzu
kzu enabled auto-merge (rebase) September 24, 2026 17:23
@kzu

kzu commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

3418 passed 3418 passed 8 skipped

🧪 Details on Microsoft Windows 10.0.26100

from retest v1.1.0 on .NET 10.0.12 with 💜 by @devlooped

@kzu

kzu commented Sep 24, 2026

Copy link
Copy Markdown
Member

@copilot test failure in CI, is it a wrong test that verified a buggy behavior?

Co-authored-by: kzu <169707+kzu@users.noreply.github.com>
auto-merge was automatically disabled September 24, 2026 17:31

Head branch was pushed to by a user without write access

Copilot AI commented Sep 24, 2026

Copy link
Copy Markdown
Contributor Author

@copilot test failure in CI, is it a wrong test that verified a buggy behavior?

Good catch — it exposed a regression from my first fix, not a buggy test. StubExtensionsFixture.Property_stubbed_by_SetupAllProperties_during_DefaultValue_Mock_has_initial_value_included_in_verification should fail verification, and I restored that behavior in c48affc while still keeping the issue #1699 fix.

@kzu

kzu commented Sep 24, 2026

Copy link
Copy Markdown
Member

@copilot verify this fix, seems weird that we'd check for the setup not being a MethodCall?

Co-authored-by: kzu <169707+kzu@users.noreply.github.com>

Copilot AI commented Sep 24, 2026

Copy link
Copy Markdown
Contributor Author

@copilot verify this fix, seems weird that we'd check for the setup not being a MethodCall?

You were right to question that check. I verified behavior and replaced it with an explicit allowlist in a6bcec8: recursion now only applies to InnerMockSetup, StubbedPropertySetup, and StubbedPropertiesSetup. That keeps #1699 fixed while preserving SetupAllProperties verification semantics.

@kzu
kzu enabled auto-merge (squash) September 24, 2026 21:01
@kzu
kzu merged commit f7be9cf into main Sep 24, 2026
4 checks passed
@kzu
kzu deleted the copilot/fix-mock-invocation-issue branch September 24, 2026 21:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

.Verify() on one mock complains over missing invocations on another mock

2 participants