Skip to content

Commit 930441d

Browse files
authored
Add overload to MockHandler to decide how mocks should be created. (#57)
1 parent eea556c commit 930441d

12 files changed

+170
-11
lines changed

AutofacContrib.NSubstitute.Tests/TypesToSkipForMockingFixture.cs

+14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Autofac.Core.Registration;
2+
using AutofacContrib.NSubstitute.MockHandlers;
23
using NUnit.Framework;
34
using System;
45
using System.Collections.Generic;
@@ -37,6 +38,19 @@ public void ManuallyAddTypeToSkip()
3738
Assert.Throws<ComponentNotRegisteredException>(() => mock.Resolve<IDependency>());
3839
}
3940

41+
[Test]
42+
public void ManuallyCheckTypeToSkip()
43+
{
44+
var mock = AutoSubstitute.Configure()
45+
.ConfigureOptions(options =>
46+
{
47+
options.MockHandlers.Add(SkipTypeMockHandler.Create<IDependency>());
48+
})
49+
.Build();
50+
51+
Assert.Throws<ComponentNotRegisteredException>(() => mock.Resolve<IDependency>());
52+
}
53+
4054
[Test]
4155
public void RegisteredTypesAreNotMocked()
4256
{

AutofacContrib.NSubstitute.sln

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ EndProject
1010
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A5ECD18F-1D42-444E-BB3A-6062D8B0E256}"
1111
ProjectSection(SolutionItems) = preProject
1212
BREAKING_CHANGES.md = BREAKING_CHANGES.md
13+
GitVersionConfig.yaml = GitVersionConfig.yaml
1314
global.json = global.json
1415
LICENSE = LICENSE
1516
logo.png = logo.png

AutofacContrib.NSubstitute/AutoSubstituteOptions.cs

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Autofac;
22
using Autofac.Builder;
3+
using AutofacContrib.NSubstitute.MockHandlers;
34
using System;
45
using System.Collections.Generic;
56
using System.ComponentModel;
@@ -10,12 +11,23 @@ public class AutoSubstituteOptions
1011
{
1112
private readonly static Func<ContainerBuilder, Autofac.IContainer> _defaultContainerBuilder = b => b.Build();
1213

14+
private readonly HashSet<Type> _typesToSkipForMocking = new HashSet<Type>();
15+
16+
public AutoSubstituteOptions()
17+
{
18+
MockHandlers = new List<MockHandler>
19+
{
20+
AlreadyExistsMockHandler.Instance,
21+
SkipTypeMockHandler.Create(_typesToSkipForMocking)
22+
};
23+
}
24+
1325
internal bool AutoInjectProperties { get; set; }
1426

1527
/// <summary>
1628
/// Gets a collection of handlers that can be used to modify mocks after they are created.
1729
/// </summary>
18-
public ICollection<MockHandler> MockHandlers { get; } = new List<MockHandler>();
30+
public ICollection<MockHandler> MockHandlers { get; }
1931

2032
/// <summary>
2133
/// Gets a collection of delegates that can augment the registrations of objects created but not registered.
@@ -25,9 +37,9 @@ public class AutoSubstituteOptions
2537
/// <summary>
2638
/// Gets a collection of types that will be skipped during generation of NSubstitute mocks.
2739
/// </summary>
28-
[Obsolete]
40+
[Obsolete("Use a custom MockHandler instead")]
2941
[EditorBrowsable(EditorBrowsableState.Never)]
30-
public ICollection<Type> TypesToSkipForMocking { get; } = new HashSet<Type>();
42+
public ICollection<Type> TypesToSkipForMocking => _typesToSkipForMocking;
3143

3244
/// <summary>
3345
/// Gets or sets a flag indicating whether mocks should be excluded for provided values. This will automatically add values given to Provide methods to <see cref="TypesToSkipForMocking"/>.

AutofacContrib.NSubstitute/AutoSubstituteOptionsExtensions.cs

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Autofac;
22
using Autofac.Core.Activators.Reflection;
3+
using AutofacContrib.NSubstitute.MockHandlers;
34
using System.Reflection;
45

56
namespace AutofacContrib.NSubstitute

AutofacContrib.NSubstitute/MockHandler.cs

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Autofac;
2+
using AutofacContrib.NSubstitute.MockHandlers;
23
using NSubstitute.Core;
34
using System;
45

@@ -20,6 +21,16 @@ protected MockHandler()
2021
/// <param name="type">The type the mock was created for.</param>
2122
/// <param name="context">The current component context.</param>
2223
/// <param name="substitutionContext">The current substitution context.</param>
23-
protected internal abstract void OnMockCreated(object instance, Type type, IComponentContext context, ISubstitutionContext substitutionContext);
24+
protected internal virtual void OnMockCreated(object instance, Type type, IComponentContext context, ISubstitutionContext substitutionContext)
25+
{
26+
}
27+
28+
/// <summary>
29+
/// Provides a way to manage the initial creation of mocks. Defaults to creating for all types.
30+
/// </summary>
31+
/// <param name="context">Context of currently being created mock.</param>
32+
protected internal virtual void OnMockCreating(MockCreatingContext context)
33+
{
34+
}
2435
}
2536
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace AutofacContrib.NSubstitute.MockHandlers
2+
{
3+
internal class AlreadyExistsMockHandler : MockHandler
4+
{
5+
public static MockHandler Instance { get; } = new AlreadyExistsMockHandler();
6+
7+
private AlreadyExistsMockHandler()
8+
{
9+
}
10+
11+
protected internal override void OnMockCreating(MockCreatingContext context)
12+
{
13+
if (context.HasRegistrations)
14+
{
15+
context.DoNotCreate();
16+
}
17+
}
18+
}
19+
}

AutofacContrib.NSubstitute/MockHandlers/AutoPropertyInjectorMockHandler.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
using NSubstitute.Core;
33
using System;
44

5-
namespace AutofacContrib.NSubstitute
5+
namespace AutofacContrib.NSubstitute.MockHandlers
66
{
77
internal class AutoPropertyInjectorMockHandler : MockHandler
88
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System;
2+
3+
namespace AutofacContrib.NSubstitute.MockHandlers
4+
{
5+
/// <summary>
6+
/// Context for the mock currently being created.
7+
/// </summary>
8+
public class MockCreatingContext
9+
{
10+
internal MockCreatingContext(Type type, bool hasRegistrations)
11+
{
12+
Type = type;
13+
ShouldCreate = true;
14+
HasRegistrations = hasRegistrations;
15+
}
16+
17+
/// <summary>
18+
/// Gets whether the type is already registered.
19+
/// </summary>
20+
public bool HasRegistrations { get; }
21+
22+
internal bool ShouldCreate { get; private set; }
23+
24+
/// <summary>
25+
/// Gets the type of the mock being created.
26+
/// </summary>
27+
public Type Type { get; }
28+
29+
/// <summary>
30+
/// Marks the current mark to be created. A call to <see cref="DoNotCreate"/> may change this state if called later.
31+
/// </summary>
32+
public void Create()
33+
{
34+
ShouldCreate = true;
35+
}
36+
37+
/// <summary>
38+
/// Marks the current mark to not be created. A call to <see cref="Create"/> may change this state if called later.
39+
/// </summary>
40+
public void DoNotCreate()
41+
{
42+
ShouldCreate = false;
43+
}
44+
}
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using Autofac;
2+
using NSubstitute.Core;
3+
using System;
4+
using System.Collections.Generic;
5+
6+
namespace AutofacContrib.NSubstitute.MockHandlers
7+
{
8+
/// <summary>
9+
/// An implementation of a <see cref="MockHandler"/> that will skip creation of mocks of type <typeparamref name="T"/>.
10+
/// </summary>
11+
public class SkipTypeMockHandler : MockHandler
12+
{
13+
private readonly IEnumerable<Type> _types;
14+
15+
/// <summary>
16+
/// Create a <see cref="MockHandler"/> that skips <typeparamref name="T"/>.
17+
/// </summary>
18+
/// <returns>A mock handler to skip supplied type.</returns>
19+
public static MockHandler Create<T>() => Create(typeof(T));
20+
21+
/// <summary>
22+
/// Create a <see cref="MockHandler"/> that skips all types contained in <paramref name="types"/>.
23+
/// </summary>
24+
/// <param name="types">List of types to return.</param>
25+
/// <returns>A mock handler to skip supplied types.</returns>
26+
public static MockHandler Create(params Type[] types) => new SkipTypeMockHandler(types);
27+
28+
/// <summary>
29+
/// Create a <see cref="MockHandler"/> that skips all types contained in <paramref name="types"/>.
30+
/// </summary>
31+
/// <param name="types">List of types to return.</param>
32+
/// <returns>A mock handler to skip supplied types.</returns>
33+
public static MockHandler Create(IEnumerable<Type> types) => new SkipTypeMockHandler(types);
34+
35+
private SkipTypeMockHandler(IEnumerable<Type> types)
36+
{
37+
_types = types;
38+
}
39+
40+
protected internal sealed override void OnMockCreated(object instance, Type type, IComponentContext context, ISubstitutionContext substitutionContext)
41+
=> base.OnMockCreated(instance, type, context, substitutionContext);
42+
43+
protected internal override void OnMockCreating(MockCreatingContext context)
44+
{
45+
foreach (var type in _types)
46+
{
47+
if (type == context.Type)
48+
{
49+
context.DoNotCreate();
50+
}
51+
}
52+
}
53+
}
54+
}

AutofacContrib.NSubstitute/NSubstituteRegistrationHandler.cs

+6-5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Autofac.Builder;
66
using Autofac.Core;
77
using Autofac.Features.Decorators;
8+
using AutofacContrib.NSubstitute.MockHandlers;
89
using NSubstitute;
910
using NSubstitute.Core;
1011

@@ -60,14 +61,14 @@ public IEnumerable<IComponentRegistration> RegistrationsFor
6061
service is DecoratorService)
6162
return Enumerable.Empty<IComponentRegistration>();
6263

63-
#pragma warning disable CS0612 // Type or member is obsolete
64-
if (_options.TypesToSkipForMocking.Contains(typedService.ServiceType))
65-
#pragma warning restore CS0612 // Type or member is obsolete
64+
var context = new MockCreatingContext(typedService.ServiceType, registrationAccessor(service).Any());
65+
66+
foreach (var handler in _options.MockHandlers)
6667
{
67-
return Enumerable.Empty<IComponentRegistration>();
68+
handler.OnMockCreating(context);
6869
}
6970

70-
if (registrationAccessor(service).Any())
71+
if (!context.ShouldCreate)
7172
{
7273
return Enumerable.Empty<IComponentRegistration>();
7374
}

AutofacContrib.NSubstitute/SubstituteForBuilderExtensions.cs

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using NSubstitute.Core;
22
using Autofac;
3+
using AutofacContrib.NSubstitute.MockHandlers;
34

45
namespace AutofacContrib.NSubstitute
56
{

GitVersionConfig.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
mode: ContinuousDelivery
2-
next-version: 6.1.0
2+
next-version: 6.2.0
33
branches: {}

0 commit comments

Comments
 (0)