Skip to content

Commit 18add29

Browse files
#184: Cache instances while setting up the ctor (#185)
1 parent 629bf06 commit 18add29

File tree

2 files changed

+38
-25
lines changed

2 files changed

+38
-25
lines changed

Moq.AutoMock.Tests/DescribeCreateInstance.cs

+23-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,6 @@ public void It_throws_when_creating_object_with_recursive_dependency()
153153
Assert.IsTrue(e.Message.StartsWith($"Did not find a best constructor for `{typeof(WithRecursiveDependency)}`"));
154154
}
155155

156-
157156
[TestMethod]
158157
[Description("Issue 123")]
159158
public void It_can_use_fixed_value_to_supply_string_parameter()
@@ -176,6 +175,24 @@ public void It_can_use_custom_resolver_to_supply_string_parameter()
176175
Assert.AreEqual("Test string", sut.String);
177176
}
178177

178+
[TestMethod]
179+
public void ConcreteDependencyFirst_WhenServiceIsShared_UsesResolvedInstance()
180+
{
181+
AutoMocker mocker = new();
182+
ConcreteDependencyIsFirst constructed = mocker.CreateInstance<ConcreteDependencyIsFirst>();
183+
184+
Assert.AreSame(constructed.Service, constructed.Dependency.Service);
185+
}
186+
187+
[TestMethod]
188+
public void ConcreteDependency_WhenServiceIsShared_UsesResolvedInstance()
189+
{
190+
AutoMocker mocker = new();
191+
ConcreteDependencyIsSecond constructed = mocker.CreateInstance<ConcreteDependencyIsSecond>();
192+
193+
Assert.AreSame(constructed.Service, constructed.Dependency.Service);
194+
}
195+
179196
private class CustomStringResolver : IMockResolver
180197
{
181198
public CustomStringResolver(string stringValue)
@@ -203,4 +220,9 @@ public HasStringParameter(string @string)
203220

204221
public string String { get; }
205222
}
223+
224+
225+
public record class ConcreteDependency(IService1 Service);
226+
public record class ConcreteDependencyIsFirst(ConcreteDependency Dependency, IService1 Service);
227+
public record class ConcreteDependencyIsSecond(IService1 Service, ConcreteDependency Dependency);
206228
}

Moq.AutoMock/AutoMocker.cs

+15-24
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,6 @@ public object CreateInstance(Type type, bool enablePrivate)
225225
nameof(type));
226226
}
227227

228-
CacheInstances(arguments.Zip(ctor.GetParameters(), (i, p) => (p.ParameterType, i)));
229-
230228
try
231229
{
232230
object?[] parameters = arguments.Select(x => x.Value).ToArray();
@@ -958,7 +956,6 @@ public void Verify<T, TResult>(Expression<Func<T, TResult>> expression, Times ti
958956
TryGetConstructorInvocation(serviceType, objectGraphContext, out ConstructorInfo? ctor, out IInstance[]? arguments))
959957
{
960958
constructorArgs = arguments.Select(x => x.Value).ToArray();
961-
CacheInstances(arguments.Zip(ctor.GetParameters(), (i, p) => (p.ParameterType, i)));
962959
}
963960

964961
if (Activator.CreateInstance(mockType, mockBehavior, constructorArgs) is Mock mock)
@@ -1018,43 +1015,37 @@ bool TryCreateArguments(ConstructorInfo constructor, ObjectGraphContext context,
10181015
{
10191016
return false;
10201017
}
1018+
1019+
TryCache(parameters[i].ParameterType, service);
10211020
arguments[i] = service;
10221021
}
10231022
return true;
10241023
}
1024+
1025+
}
1026+
1027+
private void TryCache(Type type, IInstance instance)
1028+
{
1029+
WithTypeMap(typeMap =>
1030+
{
1031+
if (!typeMap.TryGetValue(type, out _))
1032+
{
1033+
typeMap[type] = instance;
1034+
}
1035+
});
10251036
}
10261037

10271038
private Mock GetOrMakeMockFor(Type type)
10281039
{
10291040
if (TryResolve(type, new ObjectGraphContext(false), out IInstance? instance) &&
10301041
instance is MockInstance mockInstance)
10311042
{
1032-
WithTypeMap(typeMap =>
1033-
{
1034-
if (!typeMap.ContainsKey(type))
1035-
{
1036-
typeMap[type] = mockInstance;
1037-
}
1038-
});
1043+
TryCache(type, mockInstance);
10391044
return mockInstance.Mock;
10401045
}
10411046
throw new ArgumentException($"{type} does not resolve to a Mock");
10421047
}
10431048

1044-
internal void CacheInstances(IEnumerable<(Type, IInstance)> instances)
1045-
{
1046-
WithTypeMap(typeMap =>
1047-
{
1048-
foreach (var (type, instance) in instances)
1049-
{
1050-
if (!typeMap.ContainsKey(type))
1051-
{
1052-
typeMap[type] = instance;
1053-
}
1054-
}
1055-
});
1056-
}
1057-
10581049
private void WithTypeMap(Action<NonBlocking.ConcurrentDictionary<Type, IInstance>> onTypeMap)
10591050
{
10601051
if (TypeMap is { } typeMap)

0 commit comments

Comments
 (0)