Skip to content

NSubstitute/Castle proxy fail to create substitute that returns a derived class from abstract that satisfies interface implicitly #730

@siblount

Description

@siblount

Describe the bug
NSubstitute/Castle proxy fails to create a substitute for a concrete class that derives from an abstract class and virtual members.

To Reproduce
Here's an example of what I am talking about:
Setup classes

namespace TestNSubstituteBS
{
    public abstract class AbstractIOContext
    {
        public abstract IDirectoryInfo CreateDirectoryInfo();
    }
}
namespace TestNSubstituteBS
{
    public class ConcreteIOContext : AbstractIOContext
    {
        public override XDirectoryInfo CreateDirectoryInfo() => new XDirectoryInfo();
    }
}
namespace TestNSubstituteBS
{
    public class XDirectoryInfo : IDirectoryInfo { }
}
namespace TestNSubstituteBS
{
    public interface IDirectoryInfo { }
}

Test code:

namespace TestNSubstituteBS.Tests
{
    [TestClass()]
    public class AbstractFactoryTests
    {
        [TestMethod]
        public void CreateTest()
        {
            var a = Substitute.For<ConcreteIOContext>(); // <--------------- fails here
            a.CreateDirectoryInfo().Returns(new XDirectoryInfo());
        }
    }
}

Running the above returns this error message...

Test method TestNSubstituteBS.Tests.AbstractFactoryTests.CreateTest threw exception: 
System.TypeLoadException: Return type in method 'Castle.Proxies.ConcreteIOContextProxy.CreateDirectoryInfo()' on type 'Castle.Proxies.ConcreteIOContextProxy' from assembly 'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not compatible with base type method 'TestNSubstituteBS.ConcreteIOContext.CreateDirectoryInfo()'.

and stack trace...

  Stack Trace: 
TypeBuilder.CreateTypeNoLock()
TypeBuilder.CreateTypeInfo()
AbstractTypeEmitter.BuildType()
BaseClassProxyGenerator.GenerateType(String name, INamingScope namingScope)
<>c__DisplayClass13_0.<GetProxyType>b__0(CacheKey cacheKey)
SynchronizedDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
BaseProxyGenerator.GetProxyType()
DefaultProxyBuilder.CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options)
ProxyGenerator.CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options)
ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] interceptors)
CastleDynamicProxyFactory.CreateProxyUsingCastleProxyGenerator(Type typeToProxy, Type[] additionalInterfaces, Object[] constructorArguments, IInterceptor[] interceptors, ProxyGenerationOptions proxyGenerationOptions)
CastleDynamicProxyFactory.GenerateTypeProxy(ICallRouter callRouter, Type typeToProxy, Type[] additionalInterfaces, Object[] constructorArguments)
CastleDynamicProxyFactory.GenerateProxy(ICallRouter callRouter, Type typeToProxy, Type[] additionalInterfaces, Object[] constructorArguments)
SubstituteFactory.Create(Type[] typesToProxy, Object[] constructorArguments, Boolean callBaseByDefault)
SubstituteFactory.Create(Type[] typesToProxy, Object[] constructorArguments)
Substitute.For(Type[] typesToProxy, Object[] constructorArguments)
Substitute.For[T](Object[] constructorArguments)
AbstractFactoryTests.CreateTest() line 18

Expected behaviour
Preferibly, that it works. Otherwise, an error message about how much of an idiot I am.
Environment:

  • NSubstitute version: 5.0.0
  • NSubstitute.Analyzers version: 1.0.16
  • Platform: .NET 6.0 Windows

Additional context

This occurs for Substitute.For<>() and Substitute.ForPartsOf<>().

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions