Skip to content

Commit 2640410

Browse files
committed
docs: Updated getting started guide and partial mock examples
1 parent 484d93a commit 2640410

File tree

2 files changed

+140
-1
lines changed

2 files changed

+140
-1
lines changed

docs/getting-started.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,15 @@ mock.Verify(x => x.GetById(1)).Once();
3939
- **Fluent API** with intelligent type inference
4040
- **First-class async** support for `Task<T>` and `ValueTask<T>`
4141
- **Partial mocks** for large interfaces
42-
- **Static/Sealed type mocking** via `Mock.Static<T>` (e.g., `DateTime.Now`)
42+
- **Static dependencies** via `Shim.For<T>()` wrapper pattern
4343
- **Generics & nested hierarchies** with full type inference
4444
- **Lie-proofing** validation against real API endpoints
4545
- **Compile-time** analyzers
4646

4747
## Next Steps
4848

4949
- See [API Reference](api-reference.md) for detailed API documentation
50+
- See [Partial Mock Examples](partial-mock-examples.md) for real-world patterns
5051
- Check [Performance](performance.md) for benchmark results
5152
- Read [Migration Guide](migration-guide.md) to migrate from Moq
5253

docs/partial-mock-examples.md

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# Partial Mock Examples
2+
3+
`Mock.Partial<T>()` is perfect for large interfaces where you only want to mock a few methods. Unmocked methods throw `NotImplementedException`.
4+
5+
## When to Use Partial Mocks
6+
7+
- **Large interfaces** with 10+ methods where you only test 2-3
8+
- **SDK clients** (Azure, AWS) with many operations
9+
- **Legacy code** with broad service contracts
10+
11+
---
12+
13+
## Example 1: Large Service Interface
14+
15+
```csharp
16+
// A typical enterprise service with many methods
17+
public interface IOrderService
18+
{
19+
Order GetById(int id);
20+
IEnumerable<Order> GetByCustomer(int customerId);
21+
IEnumerable<Order> GetPending();
22+
IEnumerable<Order> GetRecent(int days);
23+
Task<Order> CreateAsync(OrderRequest request);
24+
Task UpdateAsync(Order order);
25+
Task CancelAsync(int orderId, string reason);
26+
Task<decimal> CalculateTotalAsync(int orderId);
27+
// ... 20 more methods
28+
}
29+
30+
// Test only needs GetById - mock just that one
31+
[Fact]
32+
public void ProcessOrder_UsesOrderFromService()
33+
{
34+
var testOrder = new Order { Id = 1, Total = 100m };
35+
36+
var mock = Mock.Partial<IOrderService>()
37+
.Only(x => x.GetById(1), testOrder)
38+
.Build();
39+
40+
var processor = new OrderProcessor(mock.Object);
41+
var result = processor.Process(1);
42+
43+
Assert.Equal(100m, result.Total);
44+
mock.Verify(x => x.GetById(1)).Once();
45+
}
46+
```
47+
48+
---
49+
50+
## Example 2: Azure SDK Client Pattern
51+
52+
```csharp
53+
// Azure Blob Storage client interface (abstracted)
54+
public interface IBlobStorageClient
55+
{
56+
Task<BlobInfo> UploadAsync(string container, string path, Stream content);
57+
Task<Stream> DownloadAsync(string container, string path);
58+
Task DeleteAsync(string container, string path);
59+
Task<bool> ExistsAsync(string container, string path);
60+
IAsyncEnumerable<BlobItem> ListBlobsAsync(string container);
61+
Task<BlobProperties> GetPropertiesAsync(string container, string path);
62+
// ... many more operations
63+
}
64+
65+
[Fact]
66+
public async Task FileProcessor_ChecksExistenceBeforeDownload()
67+
{
68+
var mock = Mock.Partial<IBlobStorageClient>()
69+
.Only(x => x.ExistsAsync("docs", "readme.md"), Task.FromResult(true))
70+
.Only(x => x.DownloadAsync("docs", "readme.md"), Task.FromResult(new MemoryStream() as Stream))
71+
.Build();
72+
73+
var processor = new FileProcessor(mock.Object);
74+
await processor.ProcessFileAsync("docs", "readme.md");
75+
76+
mock.Verify(x => x.ExistsAsync("docs", "readme.md")).Once();
77+
mock.Verify(x => x.DownloadAsync("docs", "readme.md")).Once();
78+
}
79+
```
80+
81+
---
82+
83+
## Example 3: Repository with Many Query Methods
84+
85+
```csharp
86+
public interface IUserRepository
87+
{
88+
User? GetById(int id);
89+
User? GetByEmail(string email);
90+
IEnumerable<User> GetByRole(string role);
91+
IEnumerable<User> GetActive();
92+
IEnumerable<User> GetInactive();
93+
IEnumerable<User> Search(string query);
94+
Task<int> CountAsync();
95+
Task SaveAsync(User user);
96+
Task DeleteAsync(int id);
97+
}
98+
99+
[Fact]
100+
public void AuthService_FindsUserByEmail()
101+
{
102+
var testUser = new User { Id = 1, Email = "test@example.com", IsActive = true };
103+
104+
var mock = Mock.Partial<IUserRepository>()
105+
.Only(x => x.GetByEmail("test@example.com"), testUser)
106+
.Build();
107+
108+
var authService = new AuthService(mock.Object);
109+
var result = authService.Authenticate("test@example.com", "password");
110+
111+
Assert.NotNull(result);
112+
mock.Verify(x => x.GetByEmail("test@example.com")).Once();
113+
}
114+
```
115+
116+
---
117+
118+
## Full Mock vs Partial Mock
119+
120+
| Scenario | Use |
121+
|----------|-----|
122+
| Interface with 2-3 methods | `Mock.Of<T>()` |
123+
| Interface with many methods, testing few | `Mock.Partial<T>()` |
124+
| Need all methods to work | `Mock.Of<T>()` with all setups |
125+
126+
```csharp
127+
// Full mock - Setup ALL methods you call
128+
var full = Mock.Of<IOrderService>()
129+
.Setup(x => x.GetById(1), order)
130+
.Setup(x => x.CalculateTotalAsync(1), Task.FromResult(100m))
131+
.Build();
132+
133+
// Partial mock - Setup ONLY what you need
134+
var partial = Mock.Partial<IOrderService>()
135+
.Only(x => x.GetById(1), order)
136+
.Build();
137+
// CalculateTotalAsync will throw NotImplementedException if called
138+
```

0 commit comments

Comments
 (0)