Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch naming of all redirect and via terms #48

Merged
merged 4 commits into from
Dec 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ dotnet add package DivertR

# Feature Summary

1. Test double proxy framework for mocking, faking, stubbing, spying, etc. [[more]](./docs/Via.md)
2. Proxies that wrap and forward to root (original) instances so tests run against the integrated system whilst modifying and spying on specific parts as needed. [[more]](./docs/Via.md#proxy)
3. A lightweight, fluent interface for configuring proxies to redirect calls to delegates or substitute instances. [[more]](./docs/Via.md#redirect)
4. Dynamic update and reset of proxies in a running application enabling changes between tests without requiring restart and initialisation overhead. [[more]](./docs/Via.md#reset)
5. Leveraging .NET ValueTuple types for specifying named and strongly typed call arguments that can be passed and reused e.g. in call verifications. [[more]](./docs/Via.md#named-arguments)
6. Method call interception and diversion with optional relay back to the original target. [[more]](./docs/Via.md#relay)
7. Simple plugging of proxy factories into the dependency injection container by decorating and wrapping existing registrations. [[more]](./docs/DI.md#via-registration)
1. Test double proxy framework for mocking, faking, stubbing, spying, etc. [[more]](./docs/Redirect.md)
2. Proxies that wrap and forward to root (original) instances so tests run against the integrated system whilst modifying and spying on specific parts as needed. [[more]](./docs/Redirect.md#proxy)
3. A lightweight, fluent interface for configuring proxies to redirect calls to delegates or substitute instances. [[more]](./docs/Redirect.md#via)
4. Dynamic update and reset of proxies in a running application enabling changes between tests without requiring restart and initialisation overhead. [[more]](./docs/Redirect.md#reset)
5. Leveraging .NET ValueTuple types for specifying named and strongly typed call arguments that can be passed and reused e.g. in call verifications. [[more]](./docs/Redirect.md#named-arguments)
6. Method call interception and diversion with optional relay back to the original target. [[more]](./docs/Redirect.md#relay)
7. Simple plugging of proxy factories into the dependency injection container by decorating and wrapping existing registrations. [[more]](./docs/DI.md#redirect-registration)
8. Recording and verifying proxy calls. [[more]](./docs/Verify.md)

# Example Usage
Expand All @@ -48,9 +48,9 @@ public async Task GivenFooExistsInRepo_WhenGetFoo_ThenReturnsFoo_WithOk200()
};

_diverter
.Via<IFooRepository>() // Divert IFooRepository calls
.Redirect<IFooRepository>() // Redirect IFooRepository calls
.To(x => x.GetFooAsync(foo.Id)) // matching this method and argument
.Redirect(() => Task.FromResult(foo)); // by redirecting to this delegate
.Via(() => Task.FromResult(foo)); // via this delegate

// ACT
var response = await _fooClient.GetFooAsync(foo.Id);
Expand All @@ -66,9 +66,9 @@ public async Task GivenFooRepoException_WhenGetFoo_ThenReturns500InternalServerE
{
// ARRANGE
_diverter
.Via<IFooRepository>()
.Redirect<IFooRepository>()
.To(x => x.GetFooAsync(Is<Guid>.Any))
.Redirect(() => throw new Exception());
.Via(() => throw new Exception());

// ACT
var response = await _fooClient.GetFooAsync(Guid.NewGuid());
Expand All @@ -83,7 +83,7 @@ public async Task GivenFooRepoException_WhenGetFoo_ThenReturns500InternalServerE
For more examples and a demonstration of setting up a test harness for a WebApp see this [WebApp Testing Sample](./test/DivertR.WebAppTests/WebAppTests.cs)
or follow below for a quickstart:

* [Vias](./docs/Via.md) for creating and configuring proxies.
* [Redirects](./docs/Redirect.md) for creating and configuring proxies.
* [Dependency Injection](./docs/DI.md) integration.
* [Recording and Verifying](./docs/Verify.md) calls.
* [About](./docs/About.md) DivertR.
4 changes: 2 additions & 2 deletions docs/About.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# About

DivertR is similar to well known mocking frameworks like Moq or FakeItEasy but provides additional features for dynamically manipulating the dependency injection (DI) layer at runtime.
You can redirect dependency calls to test doubles, such as substitute instances, mocks or delegates, and then optionally relay them back to the original services.
DivertR is similar to well known mocking frameworks like Moq or FakeItEasy but provides additional features for use with integration testing such as dynamically manipulating the dependency injection (DI) layer at runtime.
You can redirect calls to test doubles, such as substitute instances, mocks or delegates, and then optionally relay them back to the original services.

Many developers are already enjoying the benefits of in-process component/integration testing using Microsoft's [WebApplicationFactory (TestServer)](https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests)
which also lets you customise the DI configuration, e.g. to substitute test doubles, but this can only be done once (per TestServer instantiation).
Expand Down
60 changes: 30 additions & 30 deletions docs/DI.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Dependency Injection

DivertR is designed to be embedded easily and transparently into the dependency injection (DI) container to facilitate testing an integrated, wired-up system.
It does this by decorating existing DI service registrations with [Vias](./Via.md) that replace the originals.
These Vias create proxies that wrap the instances resolved from the originals as their default targets or *roots*.
It does this by decorating existing DI service registrations with [Redirects](./Redirect.md) that replace the originals.
These Redirects create proxies that wrap the instances resolved from the originals as their default targets or *roots*.

By default Via proxies transparently forward calls to their roots and therefore, in this initial state, the behaviour of the DI system is unchanged.
By default Redirect proxies transparently forward calls to their roots and therefore, in this initial state, the behaviour of the DI system is unchanged.
Then specific parts of the system can be modified as required by dynamically updating and resetting proxies between tests without requiring restart.

# .NET ServiceCollection
Expand All @@ -19,17 +19,17 @@ services.AddSingleton<IBarFactory, BarFactory>();
services.AddSingleton<IEtc, Etc>();
```

# Via Registration
# Redirect Registration

First instantiate an instance of the `Diverter` class and *register* one or more DI service types of interest that you would like be wrapped as Via proxies:
First instantiate an instance of the `Diverter` class and *register* one or more DI service types of interest that you would like be wrapped as Redirect proxies:

```csharp
var diverter = new Diverter()
.Register<IFoo>()
.Register<IBarFactory>();
```

Then call `Divert`, a provided `IServiceCollection` extension method, to install the registered types as `Via` decorators:
Then call `Divert`, a provided `IServiceCollection` extension method, to install the registered types as `Redirect` decorators:

```csharp
services.Divert(diverter);
Expand All @@ -48,25 +48,25 @@ IFoo demo = new Foo();
Console.WriteLine(demo.Name); // "Foo";
```

# Via Configuration
# Redirect Configuration

The resolved `IFoo` instance above is a Via proxy generated by the underlying `IVia<IFoo>` decorator that uses the original DI registration to initialise the proxy root.
In its initial state the `IFoo` proxy forwards all calls directly to its root. However, this behaviour can be modified by obtaining the underlying `Via`
from the `Diverter` instance and adding a *redirect*:
The resolved `IFoo` instance above is a Redirect proxy generated by the underlying `IRedirect<IFoo>` decorator that uses the original DI registration to initialise the proxy root.
In its initial state the `IFoo` proxy forwards all calls directly to its root. However, this behaviour can be modified by obtaining the underlying `Redirect`
from the `Diverter` instance and adding a *Via*:

```csharp
// Obtain the underlying Via from the diverter instance
IVia<IFoo> fooVia = diverter.Via<IFoo>();
// Obtain the underlying Redirect from the diverter instance
IRedirect<IFoo> fooRedirect = diverter.Redirect<IFoo>();

fooVia
fooRedirect
.To(x => x.Name)
.Redirect(call => $"{call.Root.Name} diverted");
.Via(call => $"{call.Root.Name} diverted");

var foo = provider.GetService<IFoo>();
Console.WriteLine(foo.Name); // "Foo diverted"
```

Any redirects added to the `Via` are applied to all its existing proxies and any resolved afterwards:
Any Vias added to the `Redirect` are applied to all its existing proxies and any resolved afterwards:

```csharp
var foo2 = provider.GetService<IFoo>();
Expand All @@ -76,7 +76,7 @@ Console.WriteLine(foo2.Name); // "Foo2 diverted"

# Reset

All Vias registered in the `Diverter` instance and resolved proxies can be *reset* to their initial state with a single call:
All Redirects registered in the `Diverter` instance and resolved proxies can be *reset* to their initial state with a single call:

```csharp
diverter.ResetAll();
Expand All @@ -85,49 +85,49 @@ Console.WriteLine(foo.Name); // "Foo"
Console.WriteLine(foo2.Name); // "Foo2"
```

# RedirectVia
# ViaRedirect

Sometimes a test needs to manipulate instances that are not directly created by the DI container.
E.g. if we assume the `IBarFactory` service registration given above is a factory that creates `IBar` instances.
These instances can be wrapped and managed as Via proxies by calling `RedirectVia` as follows:
These instances can be wrapped and managed as Redirect proxies by calling `ViaRedirect` as follows:

```csharp

// Wrap created IBar instances as Via proxies and get a reference their Via
IVia<IBar> barVia = diverter
.Via<IBarFactory>()
// Wrap created IBar instances as Redirect proxies and get a reference their Redirect
IRedirect<IBar> barRedirect = diverter
.Redirect<IBarFactory>()
.To(x => x.Create(Is<string>.Any))
.RedirectVia();
.ViaRedirect();

var barFactory = provider.GetService<IBarFactory>();
IBar bar = barFactory.Create("MrBar"); // The Create call now returns IBar proxies
Console.WriteLine(bar.Name); // "MrBar"

// Add a redirect to alter behaviour
barVia
// Add a Via to alter behaviour
barRedirect
.To(x => x.Name)
.Redirect(call => call.Root.Name + " diverted");
.Via(call => call.Root.Name + " diverted");

Console.WriteLine(bar.Name); // "MrBar diverted"

// ResetAll also resets RedirectVias
// ResetAll also resets ViaRedirects
diverter.ResetAll();
Console.WriteLine(bar.Name); // "MrBar"
```

# Proxy Lifetime

DivertR aims to leave the original system behaviour unchanged and therefore
when existing DI registrations are replaced by Via decorators the lifetime of the registration is preserved.
when existing DI registrations are replaced by Redirect decorators the lifetime of the registration is preserved.

For multiple instance registrations such as transients, a separate proxy instance is created for each but all from the same Via instance.
In other words all proxies resolved from a Via decorated registration are managed from this single Via.
For multiple instance registrations such as transients, a separate proxy instance is created for each but all from the same Redirect instance.
In other words all proxies resolved from a Redirect decorated registration are managed from this single Redirect.

# Dispose

If a DI created root instance implements the `IDisposable` interface then the DI container manages its disposal, as usual, according to its registration lifetime.

If a DI Via proxy is an `IDisposable` then **only** the proxy instance is disposed by the DI container and not the root.
If a DI Redirect proxy is an `IDisposable` then **only** the proxy instance is disposed by the DI container and not the root.
In this case the responsibilty is left to the proxy for forwarding the dispose call to its root (and it does this by default).

The above also applies to `IAsyncDisposable`.
Loading