automock icon indicating copy to clipboard operation
automock copied to clipboard

refactor(core): replace .boundaries() with .collaborate() and .exclude()

Open omermorad opened this issue 1 month ago • 1 comments

Summary

Replaces the .boundaries() API with semantically clearer .collaborate() and .exclude() methods. This refactoring improves API clarity and provides identity-based mocking that is stable across refactoring.

Breaking Changes

  • Removed: .boundaries() method
  • Replaced with: .collaborate() (no params) + .exclude([...]) (min 1 class required)
  • Internal: Mode type changed from 'boundaries' to 'collaborate'
  • Internal: boundaryClasses renamed to excludedClasses

New API

// Before (boundaries)
TestBed.sociable(UserService)
  .boundaries([ExpensiveService])
  .compile()

// After (collaborate)
TestBed.sociable(UserService)
  .collaborate()
  .exclude([ExpensiveService])
  .compile()

// Simple case (no exclusions)
TestBed.sociable(UserService)
  .collaborate()
  .compile()

Benefits

Clear semantics: .collaborate() communicates intent better than .boundaries()
Identity-based mocking: Exclusions based on class identity, not graph position (refactor-stable)
Type safety: TypeScript enforces minimum 1 item in exclude array via tuple type [Type, ...Type[]]
Natural boundaries preserved: Token injections still auto-mocked
.mock() still works: Can customize excluded classes or mock additional ones

Technical Details

Why This Change?

The term "boundaries" was semantically confusing:

  • Sounded like: Creating barriers/isolation at edges
  • Actually did: Blacklist specific classes to mock, everything else real
  • Problem: Didn't clearly communicate "most dependencies collaborate naturally"

The new API aligns with Martin Fowler's "Sociable Tests" concept where dependencies work together by default, with selective exclusions for expensive/external concerns.

Identity-Based vs Position-Based Mocking

Identity-based (new API):

.exclude([StripeClient])  // "Mock StripeClient wherever it appears"

✅ Stable across refactoring - if StripeClient moves deeper in the graph, it stays mocked

Position-based (hypothetical "mock leaves"):

.mockLeaves()  // "Mock whatever is at graph edges"

❌ Fragile - refactoring changes which classes are leaves, breaking tests

Files Changed

  • packages/core/src/services/builders/sociable-unit-builder.ts - Core API
  • packages/core/src/errors/dependency-not-configured.error.ts - Error types
  • packages/core/src/services/dependency-resolver.ts - Resolution logic
  • packages/core/src/services/unit-mocker.ts - Options types
  • Test files renamed and updated (all 105 tests passing)

Test Coverage

Test Suites: 8 passed, 8 total
Tests:       105 passed, 105 total
Coverage:    95.27% statements, 82.92% branches

Migration Guide

Users on v4 beta should update:

// Old
.boundaries([ClassA, ClassB])

// New
.collaborate()
.exclude([ClassA, ClassB])

Since this is a beta release, breaking changes are acceptable for semantic improvements.

omermorad avatar Nov 06 '25 13:11 omermorad

Codecov Report

:x: Patch coverage is 93.33333% with 1 line in your changes missing coverage. Please review. :white_check_mark: Project coverage is 93.73%. Comparing base (7427aff) to head (2a31176). :warning: Report is 1 commits behind head on next.

Files with missing lines Patch % Lines
...ore/src/services/builders/sociable-unit-builder.ts 92.30% 0 Missing and 1 partial :warning:
Additional details and impacted files
@@            Coverage Diff             @@
##             next     #912      +/-   ##
==========================================
+ Coverage   93.07%   93.73%   +0.65%     
==========================================
  Files          26       26              
  Lines         650      654       +4     
  Branches      109      109              
==========================================
+ Hits          605      613       +8     
+ Misses         37       33       -4     
  Partials        8        8              
Flag Coverage Δ
core.unit 94.03% <93.33%> (+1.42%) :arrow_up:
di.inversify 100.00% <ø> (ø)
di.nestjs 87.25% <ø> (ø)
doubles.jest 100.00% <ø> (ø)
doubles.sinon 100.00% <ø> (ø)
doubles.vitest 100.00% <ø> (ø)
unit 77.27% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

:rocket: New features to boost your workflow:
  • :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • :package: JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

codecov[bot] avatar Nov 06 '25 13:11 codecov[bot]