{"id":37034691,"url":"https://github.com/geoder101/moqproxy","last_synced_at":"2026-01-14T04:03:49.501Z","repository":{"id":319739410,"uuid":"1079464354","full_name":"geoder101/MoqProxy","owner":"geoder101","description":"A Moq extension that allows you to set up a mock to proxy/forward all calls to a real implementation, while still being able to verify calls and override specific behaviors.","archived":false,"fork":false,"pushed_at":"2025-11-07T11:45:14.000Z","size":219,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-13T21:44:52.590Z","etag":null,"topics":["mock","moq","proxy","testing","unittest"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/geoder101.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-19T21:18:44.000Z","updated_at":"2025-11-07T11:45:18.000Z","dependencies_parsed_at":null,"dependency_job_id":"be197792-0039-48fa-a9b7-9bddf1e6427f","html_url":"https://github.com/geoder101/MoqProxy","commit_stats":null,"previous_names":["geoder101/moqproxy"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/geoder101/MoqProxy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geoder101%2FMoqProxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geoder101%2FMoqProxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geoder101%2FMoqProxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geoder101%2FMoqProxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/geoder101","download_url":"https://codeload.github.com/geoder101/MoqProxy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geoder101%2FMoqProxy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28409000,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mock","moq","proxy","testing","unittest"],"created_at":"2026-01-14T04:03:48.739Z","updated_at":"2026-01-14T04:03:49.494Z","avatar_url":"https://github.com/geoder101.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MoqProxy\n\n[![NuGet](https://img.shields.io/nuget/v/geoder101.MoqProxy.svg)](https://www.nuget.org/packages/geoder101.MoqProxy/)\n\nA powerful extension for [Moq](https://github.com/devlooped/moq) that enables **proxy pattern mocking** - forward calls\nfrom a mock to a real implementation while maintaining full verification capabilities.\n\n## Why MoqProxy?\n\nMoqProxy bridges the gap between full mocking and real implementations, giving you the best of both worlds:\n\n- **Verify interactions** - Use Moq's `Verify()` to assert method calls on the real implementation\n- **Selective overrides** - Override specific methods/properties while forwarding everything else\n- **Integration testing** - Test decorators and wrappers with real dependencies\n- **Spy pattern** - Observe and verify behavior without changing it\n- **Works with interfaces AND classes** - Unlike `CallBase`, works seamlessly with interface mocks\n\n## How is this different from `CallBase = true`?\n\n| Feature                      | MoqProxy (`SetupAsProxy`)                  | `CallBase = true`                             |\n|------------------------------|--------------------------------------------|-----------------------------------------------|\n| **Use case**                 | ✅ Spy on existing objects, test decorators | ⚠️ Partial mocking of concrete classes        |\n| **Works with interfaces**    | ✅ Yes - forwards to any implementation     | ❌ No - interfaces have no base implementation |\n| **Separate implementation**  | ✅ Forwards to a different instance         | ❌ Only calls the mock's own base methods      |\n| **Property synchronization** | ✅ Mock and implementation stay in sync     | ⚠️ Only if mock is the implementation         |\n| **Event forwarding**         | ✅ Event subscriptions forwarded            | ⚠️ Only if mock is the implementation         |\n| **Generic method support**   | ✅ Full support via custom interceptor      | ✅ Supported                                   |\n| **Indexer support**          | ✅ 1-2 parameter indexers                   | ✅ Supported                                   |\n\n**Key Difference:** `CallBase = true` only works with **abstract or virtual members of the mocked class itself**.\n`SetupAsProxy` works with **interfaces** and forwards calls to a **separate implementation instance**, making it perfect\nfor the spy pattern and testing decorators.\n\n### Example Comparison\n\n```csharp\npublic interface ICalculator\n{\n    int Add(int x, int y);\n}\n\npublic class Calculator : ICalculator\n{\n    public int Add(int x, int y) =\u003e x + y;\n}\n\n// ❌ This DOESN'T work - interface has no base implementation\nvar mock = new Mock\u003cICalculator\u003e { CallBase = true };\nmock.Object.Add(2, 3); // Throws - no implementation!\n\n// ✅ This DOES work - forwards to real implementation\nvar realCalc = new Calculator();\nvar mock = new Mock\u003cICalculator\u003e();\nmock.SetupAsProxy(realCalc);\nmock.Object.Add(2, 3); // Returns 5, calls realCalc.Add(2, 3)\n```\n\n## Installation\n\n```bash\ndotnet add package geoder101.MoqProxy\n```\n\n### Microsoft Dependency Injection Integration\n\nFor ASP.NET Core and Microsoft.Extensions.DependencyInjection scenarios, install the integration package:\n\n[![NuGet](https://img.shields.io/nuget/v/geoder101.MoqProxy.DependencyInjection.Microsoft.svg)](https://www.nuget.org/packages/geoder101.MoqProxy.DependencyInjection.Microsoft/)\n\n```bash\ndotnet add package geoder101.MoqProxy.DependencyInjection.Microsoft\n```\n\nThis package allows you to wrap services registered in your DI container with Moq proxies, making it easy to verify\ncalls and spy on real implementations in integration tests. See\nthe [package README](src/MoqProxy.DependencyInjection.Microsoft/README.md) for details.\n\n## Quick Start\n\n```csharp\nusing Moq;\nusing MoqProxy;\n\n// Create a mock and a real implementation\nvar realService = new MyService();\nvar mock = new Mock\u003cIMyService\u003e();\n\n// Set up the mock to proxy all calls to the real implementation\nmock.SetupAsProxy(realService);\n\n// Use the mock - calls are forwarded to realService\nmock.Object.DoSomething();\n\n// Verify the call was made\nmock.Verify(m =\u003e m.DoSomething(), Times.Once);\n```\n\n## Features\n\n### ✅ Properties\n\n- Read-only properties\n- Write-only properties\n- Read-write properties\n- Complex type properties (collections, dictionaries, etc.)\n- Null value handling\n- State synchronization - changes to mock properties are reflected in the implementation and vice versa\n\n### ✅ Events\n\n- Event subscription (`+=`) forwarding to implementation\n- Event unsubscription (`-=`) forwarding to implementation\n- Standard `EventHandler` and `EventHandler\u003cTEventArgs\u003e` patterns\n- Custom delegate types\n- Multiple handlers on the same event\n- Events raised by implementation invoke handlers subscribed to mock\n\n### ✅ Methods\n\n- Void methods\n- Methods with return values\n- Methods with 0-4+ parameters\n- Method overloads\n- Generic methods - full support including type inference\n- Async methods - `Task` and `Task\u003cT\u003e`\n- Ref/out parameters - automatic forwarding with verification support\n- Various return types (primitives, objects, collections, etc.)\n\n### ✅ Indexers\n\n- Single-parameter indexers (`this[int index]`)\n- Multi-parameter indexers (`this[int x, int y]`)\n- Read-only indexers\n- Write-only indexers (limited support due to Moq constraints)\n\n### ✅ Advanced Features\n\n- Spy pattern - Intercept and observe method calls with callbacks while forwarding to implementation\n- Selective override - Override specific behaviors while keeping others proxied\n- Mock reset - Call `mock.Reset()` then `SetupAsProxy()` again to restore proxying\n- Multiple instances - Proxy multiple implementations with different mocks\n- Upstream access - Retrieve the upstream implementation instance from a mock proxy\n\n### ✅ Spy Pattern\n\nSpy on specific methods to observe parameters and return values while still forwarding calls to the real implementation:\n\n```csharp\nvar impl = new Calculator();\nvar mock = new Mock\u003cICalculator\u003e();\nmock.SetupAsProxy(impl);\n\n// Spy on a method with a callback that receives parameters\nvar capturedParams = new List\u003c(int x, int y)\u003e();\nmock.Spy(\n    m =\u003e m.Add(It.IsAny\u003cint\u003e(), It.IsAny\u003cint\u003e()),\n    (int x, int y) =\u003e capturedParams.Add((x, y)));\n\nvar result1 = mock.Object.Add(2, 3); // Returns 5, forwards to impl\nvar result2 = mock.Object.Add(10, 20); // Returns 30, forwards to impl\n\n// The callback captured all parameters\nAssert.Equal(2, capturedParams.Count);\nAssert.Equal((2, 3), capturedParams[0]);\nAssert.Equal((10, 20), capturedParams[1]);\n\n// You can also capture the return value\nvar capturedResults = new List\u003c(int x, int y, int result)\u003e();\nmock.Spy(\n    m =\u003e m.Add(It.IsAny\u003cint\u003e(), It.IsAny\u003cint\u003e()),\n    (int x, int y, int result) =\u003e capturedResults.Add((x, y, result)));\n\nmock.Object.Add(5, 7); // Returns 12\nAssert.Equal((5, 7, 12), capturedResults[0]);\n\n// Verify the calls were made\nmock.Verify(m =\u003e m.Add(It.IsAny\u003cint\u003e(), It.IsAny\u003cint\u003e()), Times.Exactly(3));\n```\n\n### ✅ Accessing Upstream Implementation\n\nRetrieve the real implementation instance from a mock proxy:\n\n```csharp\nvar impl = new Calculator();\nvar mock = new Mock\u003cICalculator\u003e();\nmock.SetupAsProxy(impl);\n\n// Get the upstream implementation (returns null if not a proxy)\nvar upstream = MockProxy.GetUpstreamInstance(mock.Object);\nAssert.NotNull(upstream);\nAssert.Same(impl, upstream);\n\n// Get the Mock\u003cT\u003e from any mock instance (returns null if not a mock)\nvar retrievedMock = MockProxy.GetMock(mock.Object);\nAssert.NotNull(retrievedMock);\nAssert.Same(mock, retrievedMock);\n```\n\n## Usage Examples\n\n### Basic Proxying\n\n```csharp\nvar impl = new Calculator();\nvar mock = new Mock\u003cICalculator\u003e();\nmock.SetupAsProxy(impl);\n\nvar result = mock.Object.Add(2, 3);\nAssert.Equal(5, result);\n\nmock.Verify(m =\u003e m.Add(2, 3), Times.Once);\n```\n\n### Selective Override\n\n```csharp\nvar impl = new Calculator();\nvar mock = new Mock\u003cICalculator\u003e();\nmock.SetupAsProxy(impl);\n\n// Override specific behavior\nmock.Setup(m =\u003e m.Add(2, 3)).Returns(100);\n\n// This call uses the override\nAssert.Equal(100, mock.Object.Add(2, 3));\n\n// Other calls are forwarded to the real implementation\nAssert.Equal(7, mock.Object.Add(3, 4));\n```\n\n### Testing Decorators\n\nThis is where MoqProxy really shines - testing decorator patterns:\n\n```csharp\npublic class CachingCalculatorDecorator : ICalculator\n{\n    private readonly ICalculator _inner;\n    private readonly Dictionary\u003c(int, int), int\u003e _cache = new();\n\n    public CachingCalculatorDecorator(ICalculator inner)\n    {\n        _inner = inner;\n    }\n\n    public int Add(int x, int y)\n    {\n        if (_cache.TryGetValue((x, y), out var cached))\n            return cached;\n\n        var result = _inner.Add(x, y);\n        _cache[(x, y)] = result;\n        return result;\n    }\n}\n\nvar impl = new Calculator();\nvar mock = new Mock\u003cICalculator\u003e();\nmock.SetupAsProxy(impl);\n\nvar decorator = new CachingCalculatorDecorator(mock.Object);\n\n// First call - should call through\ndecorator.Add(2, 3);\nmock.Verify(m =\u003e m.Add(2, 3), Times.Once);\n\n// Second call - should be cached\ndecorator.Add(2, 3);\nmock.Verify(m =\u003e m.Add(2, 3), Times.Once); // Still once - decorator cached it!\n```\n\n### Async Methods\n\n```csharp\npublic interface IAsyncService\n{\n    Task\u003cstring\u003e GetDataAsync(int id);\n    Task ProcessAsync();\n}\n\npublic class AsyncService : IAsyncService\n{\n    public async Task\u003cstring\u003e GetDataAsync(int id)\n    {\n        await Task.Delay(100); // Simulate async work\n        return $\"Data for ID: {id}\";\n    }\n\n    public async Task ProcessAsync()\n    {\n        await Task.Delay(100); // Simulate async processing\n    }\n}\n\nvar impl = new AsyncService();\nvar mock = new Mock\u003cIAsyncService\u003e();\nmock.SetupAsProxy(impl);\n\nvar result = await mock.Object.GetDataAsync(42);\nawait mock.Object.ProcessAsync();\n\nmock.Verify(m =\u003e m.GetDataAsync(42), Times.Once);\nmock.Verify(m =\u003e m.ProcessAsync(), Times.Once);\n```\n\n### Properties with State Synchronization\n\n```csharp\npublic interface IConfig\n{\n    string ConnectionString { get; set; }\n}\n\npublic class Config : IConfig\n{\n    public string ConnectionString { get; set; } = string.Empty;\n}\n\nvar impl = new Config { ConnectionString = \"Server=localhost\" };\nvar mock = new Mock\u003cIConfig\u003e();\nmock.SetupAsProxy(impl);\n\n// Get property\nAssert.Equal(\"Server=localhost\", mock.Object.ConnectionString);\n\n// Set property through mock\nmock.Object.ConnectionString = \"Server=production\";\n\n// Change is reflected in the implementation\nAssert.Equal(\"Server=production\", impl.ConnectionString);\n\n// Both mock and impl are synchronized\nAssert.Equal(impl.ConnectionString, mock.Object.ConnectionString);\n```\n\n### Indexers\n\n```csharp\npublic interface IMatrix\n{\n    int this[int x, int y] { get; set; }\n}\n\nvar impl = new Matrix();\nvar mock = new Mock\u003cIMatrix\u003e();\nmock.SetupAsProxy(impl);\n\n// Set through indexer\nimpl[0, 0] = 42; // Caution: `mock.Object[0, 0] = 42;` would not forward to impl due to how Moq handles indexer setters\n\n// Get through indexer\nvar value = mock.Object[0, 0];\n\nAssert.Equal(42, value);\nAssert.Equal(42, impl[0, 0]); // Synchronized\n```\n\n### Events\n\n```csharp\npublic class DataEventArgs : EventArgs\n{\n    public string Data { get; set; } = string.Empty;\n}\n\npublic interface INotifier\n{\n    event EventHandler? StatusChanged;\n    event EventHandler\u003cDataEventArgs\u003e? DataReceived;\n    void UpdateStatus();\n    void NotifyData(string data);\n}\n\npublic class Notifier : INotifier\n{\n    public event EventHandler? StatusChanged;\n    public event EventHandler\u003cDataEventArgs\u003e? DataReceived;\n\n    public void UpdateStatus()\n    {\n        StatusChanged?.Invoke(this, EventArgs.Empty);\n    }\n\n    public void NotifyData(string data)\n    {\n        DataReceived?.Invoke(this, new DataEventArgs { Data = data });\n    }\n}\n\nvar impl = new Notifier();\nvar mock = new Mock\u003cINotifier\u003e();\nmock.SetupAsProxy(impl);\n\nvar statusChangedCount = 0;\nvar receivedData = new List\u003cstring\u003e();\n\n// Subscribe to events on the mock\nmock.Object.StatusChanged += (sender, e) =\u003e statusChangedCount++;\nmock.Object.DataReceived += (sender, e) =\u003e receivedData.Add(e.Data);\n\n// When implementation raises events, handlers subscribed to mock are invoked\nmock.Object.UpdateStatus(); // Raises StatusChanged\n\nAssert.Equal(1, statusChangedCount);\n\n// Works with custom event args\nmock.Object.NotifyData(\"Hello\"); // Raises DataReceived\n\nAssert.Single(receivedData);\nAssert.Equal(\"Hello\", receivedData[0]);\n\n// Verify event-related interactions if needed\nmock.Verify(m =\u003e m.UpdateStatus(), Times.Once);\n```\n\n### Generic Methods\n\n```csharp\npublic class User\n{\n    public int Id { get; set; }\n    public string Name { get; set; } = string.Empty;\n}\n\npublic interface IRepository\n{\n    T GetById\u003cT\u003e(int id) where T : class;\n    void Save\u003cT\u003e(T entity) where T : class;\n}\n\npublic class Repository : IRepository\n{\n    public T GetById\u003cT\u003e(int id) where T : class\n    {\n        // Simulate fetching from a data source\n        return (Activator.CreateInstance(typeof(T)) as T)!;\n    }\n\n    public void Save\u003cT\u003e(T entity) where T : class\n    {\n        // Simulate saving to a data source\n    }\n}\n\nvar impl = new Repository();\nvar mock = new Mock\u003cIRepository\u003e();\nmock.SetupAsProxy(impl);\n\nvar user = mock.Object.GetById\u003cUser\u003e(123);\nmock.Object.Save(user);\n\nmock.Verify(m =\u003e m.GetById\u003cUser\u003e(123), Times.Once);\nmock.Verify(m =\u003e m.Save(user), Times.Once);\n```\n\n### Ref/Out Parameters\n\n```csharp\npublic interface IParser\n{\n    bool TryParse(string input, out int result);\n    void Increment(ref int value);\n}\n\npublic class Parser : IParser\n{\n    public bool TryParse(string input, out int result)\n    {\n        return int.TryParse(input, out result);\n    }\n\n    public void Increment(ref int value)\n    {\n        value++;\n    }\n}\n\nvar impl = new Parser();\nvar mock = new Mock\u003cIParser\u003e();\nmock.SetupAsProxy(impl);\n\n// Out parameters are automatically forwarded\nvar success = mock.Object.TryParse(\"123\", out var value);\nAssert.True(success);\nAssert.Equal(123, value);\n\n// Ref parameters work too\nint number = 5;\nmock.Object.Increment(ref number);\nAssert.Equal(6, number);\n\n// Verify calls with It.Ref\u003cT\u003e.IsAny\nmock.Verify(m =\u003e m.TryParse(\"123\", out It.Ref\u003cint\u003e.IsAny), Times.Once);\nmock.Verify(m =\u003e m.Increment(ref It.Ref\u003cint\u003e.IsAny), Times.Once);\n```\n\n## Advanced Scenarios\n\n### Reset and Reapply\n\n```csharp\nvar impl = new Calculator();\nvar mock = new Mock\u003cICalculator\u003e();\nmock.SetupAsProxy(impl);\n\n// Use the mock...\nmock.Object.Add(2, 3);\n\n// Override some behavior\nmock.Setup(m =\u003e m.Add(It.IsAny\u003cint\u003e(), It.IsAny\u003cint\u003e())).Returns(999);\n\n// Reset and reapply proxying\nmock.Reset();\nmock.SetupAsProxy(impl);\n\n// Now back to forwarding to real implementation\nAssert.Equal(5, mock.Object.Add(2, 3));\n```\n\n## Limitations\n\n- **Ref/out parameters**: Methods with ref/out parameters are automatically forwarded to the implementation. You can\n  verify calls using `It.Ref\u003cT\u003e.IsAny`, but cannot verify specific out values (Moq limitation).\n- **By-ref structs** (e.g., `Span\u003cT\u003e`, `ReadOnlySpan\u003cT\u003e`): Not supported due to C# expression tree limitations\n- **Indexers with 3+ parameters**: Limited support due to implementation complexity\n- **Write-only indexers**: Have limited support due to Moq API constraints\n\n## How It Works\n\nMoqProxy uses a sophisticated approach to enable proxy mocking:\n\n1. **Reflection \u0026 Expression Trees**: Dynamically inspects the mocked type and creates Moq setups using expression trees\n   for properties, methods, and indexers\n2. **Generic Method Handling**: Uses `MethodInfo.Invoke` for generic methods that can't be represented in expression\n   trees\n3. **Custom Interceptor**: Injects a Castle.DynamicProxy interceptor to handle edge cases and ensure all calls are\n   forwarded\n4. **Sentinel Pattern**: Uses a special `NullReturnValue` sentinel to detect when no explicit setup was matched,\n   triggering fallback to the real implementation\n\nThe library handles complex scenarios including:\n\n- Method overloads with different signatures\n- Generic methods with type inference\n- Multi-parameter indexers\n- Async/await patterns\n- Property state synchronization\n\n## Requirements\n\n- **.NET 8.0 or later** - The library targets .NET 8.0\n- **Moq 4.20.72 or later** - Core mocking framework\n- **Castle.Core** - Dependency of Moq, used for dynamic proxy generation\n\n## Building from Source\n\n### Prerequisites\n\n- [.NET 8.0 SDK](https://dotnet.microsoft.com/download/dotnet/8.0) or later\n- Git\n\n### Clone and Build\n\n```bash\n# Clone the repository\ngit clone https://github.com/geoder101/MoqProxy.git\ncd MoqProxy\n\n# Restore dependencies\ndotnet restore src/MoqProxy.sln\n\n# Build the solution\ndotnet build src/MoqProxy.sln\n\n# Run tests\ndotnet test src/MoqProxy.sln\n\n# Create NuGet packages (optional)\ndotnet pack --output out/nupkgs src/MoqProxy.sln\n```\n\n### Running the Demo\n\n```bash\ncd src/Demo\ndotnet run\n```\n\nThe demo application showcases the core functionality of MoqProxy including property synchronization, method forwarding,\ngeneric methods, and async operations.\n\n## Testing\n\nThe project includes comprehensive unit tests covering:\n\n- **Spy pattern** - Parameter capture, return value capture, callback invocation with various signatures\n- **MockProxy accessors** - Upstream instance retrieval, Mock\u003cT\u003e retrieval, null handling\n- **Property proxying** - Regular properties, read-only, write-only, state synchronization\n- **Method proxying** - Sync/async methods, various parameter counts, return types\n- **Event proxying** - Event subscription/unsubscription, standard and custom delegates, multiple handlers\n- **Generic methods** - Type inference, multiple type parameters\n- **Ref/out parameters** - Automatic forwarding and verification\n- **Indexers** - Single and multi-parameter indexers\n- **Edge cases** - Overrides, resets, interceptor behavior\n\nRun all tests:\n\n```bash\ndotnet test src/MoqProxy.sln\n```\n\n## Versioning\n\nThis project uses [Nerdbank.GitVersioning](https://github.com/dotnet/Nerdbank.GitVersioning) for automatic semantic\nversioning based on git history. Version numbers are automatically generated during build.\n\n## Contributing\n\nContributions are welcome! Please feel free to submit issues or pull requests.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE.txt](LICENSE.txt) file for details.\n\n## Related Projects\n\n- [Moq](https://github.com/devlooped/moq) - The mocking library this extends\n- [Castle.DynamicProxy](https://www.castleproject.org/projects/dynamicproxy/) - Used by Moq for proxy generation\n\n---\n\n### Co-authored with Artificial Intelligence\n\nThis repository is part of an ongoing exploration into human-AI co-creation.  \nThe code, comments, and structure emerged through dialogue between human intent and LLM reasoning — reviewed, refined,\nand grounded in human understanding.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeoder101%2Fmoqproxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgeoder101%2Fmoqproxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeoder101%2Fmoqproxy/lists"}