DryIoc icon indicating copy to clipboard operation
DryIoc copied to clipboard

UsingInTestsWithMockingLibrary - generics on constructor error

Open alansingfield opened this issue 3 years ago • 1 comments

Hello Dadhi,

https://github.com/dadhi/DryIoc/blob/master/docs/DryIoc.Docs/UsingInTestsWithMockingLibrary.md

I've just updated my DryIoc and the WithAutoMocking() call I use extensively.

For any service with a closed generic as a dependency, we get this error:

Test method MyTestMethod1 threw exception: 
    DryIoc.ContainerException: code: Error.ExpectedSingleDefaultFactory;
    message: Expecting a single default registration but found many:
    (DefaultDynamicKey(0), {FactoryID=545, Reuse=Singleton {Lifespan=1000}}), 
    (DefaultDynamicKey(1), {FactoryID=546, Reuse=Singleton {Lifespan=1000}})
    when resolving TempTest.IGeneric<Int32> as parameter "genInt"
      in resolution root TempTest+Consumer FactoryId=515
      from container without scope
     with .
    Please identify service with key, or metadata, or use Rules.WithFactorySelector to specify single registered factory.

The solution appears to be to bail out if the type specified is an open generic; we get called first with the IGeneric<>, then IGeneric<int> .


        public interface IGeneric<T> { }
        public class Consumer
        {
            public Consumer(IGeneric<int> genInt) { }
        }

        [TestMethod]
        public void MyTestMethod1()
        {
            var container = WithAutoMocking(new Container(), Reuse.Singleton);
            container.Register<Consumer>();

            var consumer = container.Resolve<Consumer>();
        }

        private IContainer WithAutoMocking(IContainer container, IReuse reuse = null) =>
            container.With(rules => rules.WithDynamicRegistration((serviceType, serviceKey) =>
            {
                if(!serviceType.IsAbstract) // Mock interface or abstract class only.
                    return null;

                // Without this check, the error occurs
                if(serviceType.IsOpenGeneric())
                    return null;

                var d = _mockRegistrations.GetOrAdd(serviceType,
                    type => new DynamicRegistration(
                        DelegateFactory.Of(r => Substitute.For(new[] { serviceType }, Empty<object>()), reuse)));

                return new[] { d };
            },
            DynamicRegistrationFlags.Service | DynamicRegistrationFlags.AsFallback));

Is this the correct approach? If so, can you update the docs please?

Thanks,

Alan.

alansingfield avatar Sep 09 '22 13:09 alansingfield

@alansingfield Thanks for reporting, I will check whats happenning.

dadhi avatar Sep 23 '22 13:09 dadhi

For any service with a closed generic as a dependency, we get this error:

@alansingfield Sorry, forgot about this issue, but this statement is interesting. Will check it sooner.

dadhi avatar Sep 28 '22 22:09 dadhi

I am updating the docs... Your condition is working just fine.

dadhi avatar Sep 29 '22 12:09 dadhi