diff --git a/docs/api-reference/fail-fast.md b/docs/api-reference/fail-fast.md
index 95ae298..c24d190 100644
--- a/docs/api-reference/fail-fast.md
+++ b/docs/api-reference/fail-fast.md
@@ -120,14 +120,15 @@ const logger = unitRef.get(Logger);
logger.log.mockReturnValue(undefined);
```
-### Option 3: Use .boundaries() (Best for Sociable)
+### Option 3: Use .collaborate() + .exclude() (Best for Sociable)
-Switch to boundaries pattern for cleaner configuration:
+Switch to collaborate pattern for cleaner configuration:
```typescript
// Instead of configuring many real dependencies
const { unit } = await TestBed.sociable(OrderService)
- .boundaries([ComplexTaxEngine]) // Avoid complex logic
+ .collaborate()
+ .exclude([ComplexTaxEngine]) // Exclude from collaboration
.compile();
// Note: Token-injected deps (DATABASE, HTTP) are auto-mocked
@@ -158,20 +159,21 @@ await TestBed.sociable(PaymentService)
- Unconfigured mocks throw immediately
- Bug caught at test time ✅
-### Less Critical in Boundaries Mode
+### Less Critical in Collaborate Mode
-With `.boundaries()`, the default is **everything real**:
+With `.collaborate()`, the default is **everything real**:
```typescript
await TestBed.sociable(OrderService)
- .boundaries([ComplexMLService]) // Avoid complex logic
+ .collaborate()
+ .exclude([ComplexMLService]) // Exclude from collaboration
.compile();
// All other deps try to instantiate as real
// If deps missing → natural constructor failure (already caught)
```
-Fail-fast still helps, but boundaries mode naturally fails if dependencies are misconfigured.
+Fail-fast still helps, but collaborate mode naturally fails if dependencies are misconfigured.
## Differences Between Test Types
@@ -194,9 +196,10 @@ const { unit } = await TestBed.sociable(Service)
.expose(RealService)
.compile();
-// Boundaries mode: Default is real → natural failures
+// Collaborate mode: Default is real → natural failures
const { unit } = await TestBed.sociable(Service)
- .boundaries([ComplexService])
+ .collaborate()
+ .exclude([ComplexService])
.compile();
```
@@ -205,13 +208,13 @@ const { unit } = await TestBed.sociable(Service)
## Best Practices
1. **Configure used methods**: Only mock methods your test actually calls
-2. **Use .boundaries() for test scope**: List classes to avoid (complex logic tested elsewhere, legacy code, third-party SDKs)
+2. **Use .collaborate() + .exclude() for test scope**: Exclude classes you want to avoid (complex logic tested elsewhere, legacy code, third-party SDKs)
3. **Tokens are auto-mocked**: Token-injected dependencies (`@Inject('DB')`) are automatically mocked
4. **Migrate gradually**: Use `.failFast({ enabled: false })` temporarily
5. **Remove `.failFast({ enabled: false })`**: Complete migration before v5.0.0
## See Also
-- [TestBed.sociable()](/docs/api-reference/testbed-sociable) - Sociable test configuration (includes `.expose()` and `.boundaries()`)
+- [TestBed.sociable()](/docs/api-reference/testbed-sociable) - Sociable test configuration (includes `.expose()` and `.collaborate() + .exclude()`)
- [Mock Configuration](/docs/api-reference/mock-configuration) - Configuring mock behavior
- [Migration Guide](/docs/migration-guides/from-automock) - Migrating to Suites
\ No newline at end of file
diff --git a/docs/api-reference/index.md b/docs/api-reference/index.md
index 0ccee53..7c6c45a 100644
--- a/docs/api-reference/index.md
+++ b/docs/api-reference/index.md
@@ -13,7 +13,7 @@ API reference for setting up and managing unit tests with Suites.
## Core APIs
- [**TestBed.solitary()**](/docs/api-reference/testbed-solitary) - Create isolated unit tests where all dependencies are automatically mocked
-- [**TestBed.sociable()**](/docs/api-reference/testbed-sociable) - Test business logic interactions with `.boundaries()` v4.0.0+ or `.expose()`
+- [**TestBed.sociable()**](/docs/api-reference/testbed-sociable) - Test business logic interactions with `.collaborate()` + `.exclude()` v4.0.0+ or `.expose()`
- [**Mock Configuration**](/docs/api-reference/mock-configuration) - Configure mock behavior with `.mock().final()` and `.mock().impl()`
- [**mock() and stub()**](/docs/api-reference/mock) - Create standalone mocks outside TestBed
- [**UnitReference**](/docs/api-reference/unit-reference) - Access mocked dependencies in tests
@@ -31,9 +31,10 @@ const { unit, unitRef } = await TestBed.solitary(UserService).compile();
### Creating a Sociable Test
```typescript
-// Recommended: boundaries (v4.0.0+)
+// Recommended: collaborate + exclude (v4.0.0+)
const { unit, unitRef } = await TestBed.sociable(UserService)
- .boundaries([ComplexService]) // List what to avoid
+ .collaborate()
+ .exclude([ComplexService]) // Exclude from collaboration
.compile();
// Alternative: expose
diff --git a/docs/api-reference/testbed-sociable.md b/docs/api-reference/testbed-sociable.md
index f59d5dc..6e65b00 100644
--- a/docs/api-reference/testbed-sociable.md
+++ b/docs/api-reference/testbed-sociable.md
@@ -30,17 +30,17 @@ TestBed.sociable(ClassUnderTest: Type): SociableTestBuilder
`SociableTestBuilder` with two configuration modes:
-### .boundaries() v4.0.0+
+### .collaborate() + .exclude() v4.0.0+
-Recommended approach. List classes to avoid - everything else runs real.
+Recommended approach. Enable natural collaboration, then exclude specific classes.
```typescript
-boundaries(): SociableTestBuilder
-boundaries(dependencies: Type[]): SociableTestBuilder
+collaborate(): SociableTestBuilderInCollaborateMode
+exclude(dependencies: [Type, ...Type[]]): SociableTestBuilderInCollaborateMode
```
:::tip Token Auto-Mocking
-Token-injected dependencies are automatically mocked. Use .boundaries() for class dependencies you want to avoid.
+Token-injected dependencies are automatically mocked. Use `.exclude()` for class dependencies you want to opt-out of collaboration.
:::
### .expose() - Alternative
@@ -57,17 +57,18 @@ Both methods only accept class constructors, not tokens.
## Examples
-### Using .boundaries()
+### Using .collaborate() + .exclude()
```typescript
const { unit, unitRef } = await TestBed.sociable(OrderService)
- .boundaries([ComplexTaxEngine]) // Avoid complex logic
+ .collaborate()
+ .exclude([ComplexTaxEngine]) // Exclude from collaboration
.compile();
-// Can retrieve boundaries (mocked)
+// Can retrieve excluded dependencies (mocked)
const taxEngine = unitRef.get(ComplexTaxEngine);
-// Cannot retrieve real dependencies
+// Cannot retrieve collaborating dependencies
// const calculator = unitRef.get(PriceCalculator); // ERROR - it's real
```
@@ -87,11 +88,11 @@ const database = unitRef.get(Database);
## What's Retrievable
-**Boundaries mode:**
-- ✅ Classes in .boundaries() array (mocked)
+**Collaborate mode:**
+- ✅ Classes in .exclude() array (mocked)
- ✅ Tokens (auto-mocked)
- ✅ Explicitly mocked dependencies
-- ❌ Real dependencies (auto-exposed, leaf classes)
+- ❌ Collaborating dependencies (real, auto-exposed)
**Expose mode:**
- ✅ Non-exposed dependencies (mocked)
@@ -101,15 +102,14 @@ const database = unitRef.get(Database);
## Mode Comparison
-| Aspect | .boundaries() | .expose() |
-|--------|---------------|-----------|
-| Default | Everything real | Everything mocked |
-| You list | What to avoid | What to keep |
+| Aspect | .collaborate() + .exclude() | .expose() |
+|--------|----------------------------|-----------|
+| Default | Everything collaborates | Everything mocked |
+| You list | What to exclude | What to keep |
| Use when | Many deps should be real | Few deps should be real |
-| Future-proof | ✅ New deps auto-tested | ⚠️ New deps ignored |
+| Refactoring-stable | ✅ New deps auto-collaborate | ⚠️ New deps ignored |
-**Example:** eight `.expose()` calls vs one `.boundaries()` call achieves the same outcome. See [Sociable Guide]
-(/docs/guides/sociable) for the comparison.
+**Example:** eight `.expose()` calls vs one `.collaborate()` call achieves the same outcome. See [Sociable Guide](/docs/guides/sociable) for the comparison.
## See Also
diff --git a/docs/changelog.md b/docs/changelog.md
index edb9656..f87ba23 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -9,7 +9,7 @@ description: Release notes and version history for Suites
## v4.0.0-beta.0 (Current - Testing)
:::warning Beta Release
-v4.0.0 is in beta for testing. Applies alpha infrastructure improvements **plus** boundaries mode and fail-fast behavior. All functionality will be backported to v3.1.0 soon.
+v4.0.0 is in beta for testing. Applies alpha infrastructure improvements **plus** collaborate/exclude API and fail-fast behavior. All functionality will be backported to v3.1.0 soon.
:::
**From Alpha:**
@@ -21,22 +21,30 @@ v4.0.0 is in beta for testing. Applies alpha infrastructure improvements **plus*
**New in Beta:**
-**`.boundaries()` API**
-Blacklist strategy for sociable tests. List classes to avoid - everything else runs real.
+**`.collaborate()` + `.exclude()` API**
+Natural collaboration strategy for sociable tests. Enable collaboration, then exclude specific classes.
```typescript
TestBed.sociable(OrderService)
- .boundaries([ComplexTaxEngine]) // Avoid complex logic
+ .collaborate()
+ .exclude([ComplexTaxEngine]) // Exclude from collaboration
.compile();
```
-**Why boundaries:**
-- Simpler when most deps should be real
-- Future-proof: new dependencies auto-tested
-- Leaf classes (no dependencies) automatically real
+**Why collaborate + exclude:**
+- **Refactoring stable**: Adding dependencies doesn't break tests
+- **Natural mental model**: Think collaboration, not avoidance
+- **Future-proof**: New dependencies auto-collaborate
+- **Clear intent**: "Exclude" is more intuitive than "boundaries"
- Tokens always auto-mocked (databases, HTTP)
-See [TestBed.sociable()](/docs/api-reference/testbed-sociable) for complete API details.
+**The refactoring stability advantage:**
+
+When you add new dependencies to your production code (e.g., adding a `Logger` or `ValidationService`), tests using `.collaborate()` continue to work because new dependencies automatically join the collaboration. You only need to `.exclude()` specific expensive or external services.
+
+This is more stable than "leaf-based" strategies where adding intermediate dependencies can break tests because the graph structure changed.
+
+See [TestBed.sociable()](/docs/api-reference/testbed-sociable) for complete API details and [Sociable Tests Guide](/docs/guides/sociable) for examples.
**Fail-Fast Behavior**
Enabled by default. Throws `DependencyNotConfiguredError` on unconfigured dependencies. Prevents false positives.
@@ -54,7 +62,7 @@ See [Fail-Fast Behavior](/docs/api-reference/fail-fast) for details and migratio
# Core package (beta)
npm install @suites/unit@beta
-# DI adapters (alpha - no boundaries/fail-fast changes)
+# DI adapters (alpha - no collaborate/exclude or fail-fast changes)
npm install @suites/di.nestjs@alpha
# or
npm install @suites/di.inversify@alpha
@@ -68,7 +76,7 @@ npm install @suites/doubles.sinon@beta
```
:::tip Why Different Versions?
-`@suites/unit` and doubles adapters are on **beta** (boundaries + fail-fast features). DI adapters remain on **alpha** - they're installed separately and don't contain the new testing logic.
+`@suites/unit` and doubles adapters are on **beta** (collaborate/exclude + fail-fast features). DI adapters remain on **alpha** - they're installed separately and don't contain the new testing logic.
:::
**Breaking Changes:**
@@ -89,7 +97,7 @@ All v4.0.0 features will be backported to v3.1.0 with no breaking changes. This
:::
**What's coming:**
-- `.boundaries()` API (opt-in)
+- `.collaborate()` + `.exclude()` API (opt-in)
- Fail-fast behavior (disabled by default, opt-in with .failFast(\{ enabled: true \}))
- Enhanced type safety
- Performance improvements
diff --git a/docs/get-started/installation.mdx b/docs/get-started/installation.mdx
index 503e174..c693566 100644
--- a/docs/get-started/installation.mdx
+++ b/docs/get-started/installation.mdx
@@ -18,7 +18,7 @@ Suites v4.0.0+ requires **Node.js 20 or higher**. Check your version with `node
## Installation
:::tip Testing Beta?
-For v4.0.0 beta with boundaries and fail-fast features, see [Changelog](/docs/changelog) for beta installation instructions.
+For v4.0.0 beta with collaborate/exclude and fail-fast features, see [Changelog](/docs/changelog) for beta installation instructions.
:::
Install Suites' core package:
diff --git a/docs/guides/fundamentals.md b/docs/guides/fundamentals.md
index c34c8e9..9c2aca0 100644
--- a/docs/guides/fundamentals.md
+++ b/docs/guides/fundamentals.md
@@ -110,7 +110,7 @@ Test one class in complete isolation. All dependencies are mocked.
See [Solitary Unit Tests](/docs/guides/solitary) for examples and usage.
**Sociable Tests**
-Test multiple business logic classes together. Use `.boundaries()` to list classes you want to avoid.
+Test multiple business logic classes together. Use `.collaborate()` + `.exclude()` to enable natural collaboration and exclude specific classes.
See [Sociable Unit Tests](/docs/guides/sociable) for examples and usage.
diff --git a/docs/guides/sociable.md b/docs/guides/sociable.md
index 65e2720..1224132 100644
--- a/docs/guides/sociable.md
+++ b/docs/guides/sociable.md
@@ -47,14 +47,14 @@ class UserService {
Two ways to configure sociable tests:
-**Option A: .boundaries() v4.0.0+** - List what to avoid, everything else is real
+**Option A: .collaborate() + .exclude() v4.0.0+** - Natural collaboration, opt-out specific classes \
**Option B: .expose()** - List what's real, everything else is mocked
-#### Step 2a: Using .boundaries() (Recommended)
+#### Step 2a: Using .collaborate() + .exclude() (Recommended)
-To test `UserService` with a real `UserApi`, list only what you DON'T want to test:
+To test `UserService` with real dependencies collaborating naturally:
-```typescript title="user.service.spec.ts (boundaries mode)" {1,14} showLineNumbers
+```typescript title="user.service.spec.ts (collaborate mode)" {1,14} showLineNumbers
import { TestBed, Mocked } from '@suites/unit';
import { UserService } from './user.service';
import { HttpService, Database } from './services';
@@ -66,14 +66,14 @@ describe('UserService Integration Tests', () => {
let httpService: Mocked;
beforeAll(async () => {
- // No boundaries needed - UserApi becomes real automatically!
+ // All dependencies collaborate naturally - UserApi becomes real!
const { unit, unitRef } = await TestBed.sociable(UserService)
- .boundaries() // No boundaries - all business logic is real
+ .collaborate() // Enable natural collaboration
.compile();
userService = unit;
- // Retrieve the mocked dependencies
+ // Retrieve the mocked dependencies (tokens are auto-mocked)
database = unitRef.get(Database);
httpService = unitRef.get(HttpService);
});
@@ -93,32 +93,33 @@ describe('UserService Integration Tests', () => {
```
**What happens here:**
-- **UserApi**: Real (automatically, since not in boundaries array)
-- **Database**: Mocked (automatically)
-- **HttpService**: Mocked (automatically)
+- **UserApi**: Real (collaborates naturally with UserService)
+- **Database**: Mocked (token injection, auto-mocked)
+- **HttpService**: Mocked (token injection, auto-mocked)
-**Benefits:** Simpler configuration, future-proof.
+**Benefits:** Natural collaboration, refactoring-stable, future-proof.
-#### Boundaries with Specific Classes
+#### Excluding Specific Classes from Collaboration
-When avoiding specific business logic classes:
+When you need to exclude expensive or external dependencies:
```typescript
const { unit, unitRef } = await TestBed.sociable(OrderService)
- .boundaries([ComplexTaxEngine]) // Avoid complex tax logic
+ .collaborate()
+ .exclude([ComplexTaxEngine]) // Exclude complex tax logic from collaboration
.compile();
-// ComplexTaxEngine is in boundaries - it's mocked
+// ComplexTaxEngine is excluded - it's mocked
const taxEngine = unitRef.get(ComplexTaxEngine);
taxEngine.calculate.mockReturnValue(100);
await unit.processOrder(order);
-// Verify interactions with the boundary
+// Verify interactions with excluded dependency
expect(taxEngine.calculate).toHaveBeenCalledWith(order.total);
```
-**Key point:** Classes in `.boundaries()` are mocked. You can configure them and verify their interactions - they act as controlled boundary points in your test.
+**Key point:** Classes in `.exclude()` are mocked and retrievable. Everything else collaborates naturally with real implementations.
#### Step 2b: Using .expose() (Alternative)
@@ -179,7 +180,7 @@ Mock configuration works the same in both modes. You can define behavior for moc
```typescript title="Configuring mocks before compilation"
beforeAll(async () => {
const { unit, unitRef } = await TestBed.sociable(UserService)
- .boundaries() // All business logic real
+ .collaborate() // All business logic collaborates
.mock(Database) // Configure specific mock behavior
.final({
saveUser: async () => 42 // Fixed return value
@@ -214,20 +215,42 @@ Even though sociable tests let you test real interactions, they should still foc
**2. Choose the Right Mode**
-**.boundaries() works best when:**
+**.collaborate() + .exclude() works best when:**
- Services have many business logic dependencies
- You want new dependencies tested automatically
-- You need future-proof tests
+- You need refactoring-stable, future-proof tests
+- You only need to exclude a few expensive/external classes
**.expose() works best when:**
- You want to test 2-3 specific class interactions
- You need fine-grained control over what's real
-- You prefer explicit configuration
+- You prefer explicit whitelisting configuration
**3. Complementary to Solitary Tests**
Sociable tests complement solitary tests - they don't replace them. Use solitary tests for detailed behavior verification and sociable tests for validating interactions.
+**4. Refactoring Stability**
+
+The `.collaborate() + .exclude()` API provides superior refactoring stability compared to other approaches:
+
+```typescript
+// With .collaborate() + .exclude()
+TestBed.sociable(OrderService)
+ .collaborate()
+ .exclude([ExpensiveMLService]) // Only exclude what's expensive
+ .compile();
+
+// ✅ Adding new dependencies? Test still works!
+// New deps automatically join collaboration
+```
+
+**Why this matters:**
+
+When you add new dependencies to your production code (e.g., adding a `Logger`), tests using `.collaborate()` continue to work because new dependencies automatically participate in natural collaboration. You only exclude specific expensive or external services.
+
+This is more stable than "leaf-based" or "whitelist" strategies where adding dependencies can break tests because they weren't in your configuration list.
+
## What's Next?
Combining solitary and sociable tests covers both independent behavior and component interactions.
diff --git a/docs/guides/virtual-di-container.md b/docs/guides/virtual-di-container.md
index 3d938a2..805328b 100644
--- a/docs/guides/virtual-di-container.md
+++ b/docs/guides/virtual-di-container.md
@@ -96,14 +96,14 @@ By auto-mocking these, Suites ensures **sociable tests are still unit tests** -
```typescript
// Even in sociable mode with many real classes
await TestBed.sociable(OrderService)
- .boundaries() // Everything real!
+ .collaborate() // Everything collaborates!
.compile();
// But @Inject('DATABASE') is still auto-mocked
// Tests run fast, never hit real database
```
-This creates **natural test boundaries** without manual configuration.
+This creates **natural separation** between business logic (real) and external I/O (mocked) without manual configuration.
## Benefits
@@ -122,5 +122,5 @@ See [Adapters](/docs/guides/adapters) for framework-specific details.
## Next Steps
- [Solitary Unit Tests](/docs/guides/solitary) - Using the virtual container in isolation mode
-- [Sociable Unit Tests](/docs/guides/sociable) - Using with boundaries/expose modes
+- [Sociable Unit Tests](/docs/guides/sociable) - Using with collaborate/exclude and expose modes
- [API Reference](/docs/api-reference/) - Technical details
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index 53b8034..d16a859 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -346,7 +346,6 @@ export default function Home(): JSX.Element {
name="description"
content="Suites automates mocking and simplifies test setup for dependency injection frameworks like NestJS and InversifyJS, reducing boilerplate code."
/>
-