nunit-console
nunit-console copied to clipboard
DependencyInjection via Autofac not working properly using NUnit console (or testcentric GUI)
In my NUnit-Test I register some services using Autofac library:
[Test]
public void Test() {
var builder = new ContainerBuilder();
builder.RegisterType(typeof(FakeServiceNoConfig)).AsSelf().As<IStartable>().SingleInstance();
IContainer container = builder.Build();
Assert.IsTrue(container.TryResolve(out IFakeServiceNoConfig? service));
container.Dispose();
}
public class FakeServiceNoConfig : IFakeServiceNoConfig, IStartable, IDisposable {
public void Start() { }
public void Dispose() { }
}
public interface IFakeServiceNoConfig { }
When I run the test using testcentric GUI or nunit3-console.exe or dotnet nunit3-netcore-console.dll I receive the following exception
System.ArgumentException : The type 'UnitTests.ServiceFactoryTest.FakeServiceNoConfig' is not assignable to service 'Autofac.IStartable'.
When I remove the IStarble form the builder, I get:
1) Failed : UnitTests.ServiceFactoryTests.ServiceWithoutConfig
Expected: True
But was: False
When I run the same using dotnet test, the test passes.
Is this an issue with NUnit Console/GUI or do I do something wrong?
Thanks a lot Daniel
Thanks for reporting this @Sputnik24
To help us out, are you able to share a csproj example that would show can the package versions and runtime for your example?
EDIT: Another option for sharing this info could be to put up a PR for your repro in our https://github.com/nunit/nunit-console.issues repo
Thanks for your comment @stevenaw
I further investigated the issue and uploaded a simplified solution which reproduced the issue: https://github.com/Sputnik24/AutofacNUnit
Details:
- There is a ServiceFactory in each class project. The implementation of the ServiceFactories is the same.
- The difference is that AutofacNUnitLib.ServiceFactory is in the same project as the FakeService, where AutofacNUnitTest.ServiceFactory is in a different project than the FakeService.
- I implemented two tests: FakeServiceSameProject, which uses AutofacNUnitLib.ServiceFactory and FakeServiceDiffProject which uses the other.
- To get additional information, the ServiceFactory in AutofacNUnitTest prints the FullName of the type to register and its iterfaces to the NUnit console.
Behavior:
- Running the test in my IDE (Rider): Both tests succeed
- Running the test using dotnet test: Both tests succed
- Running the test using either nunit3-console.exe or dotnet nunit3-netcore-console.dll: FakeServiceSameProject succeeds but FakeServiceDiffProject fails with:
C:\dev\nunit\nunit3-console.exe .\AutofacNUnitTest.dll
NUnit Console 3.16.2 (Release)
Copyright (c) 2022 Charlie Poole, Rob Prouse
Freitag, 28. Juli 2023 08:34:25
Runtime Environment
OS Version: Microsoft Windows NT 6.2.9200.0
Runtime: .NET Framework CLR v4.0.30319.42000
Test Files
.\AutofacNUnitTest.dll
AutofacNUnitLib.FakeService:
AutofacNUnitLib.IFakeService
Autofac.IStartable
System.IDisposable
Errors, Failures and Warnings
1) Error : AutofacNUnitTest.ServiceFactoryTests.FakeServiceDiffProjects
System.ArgumentException : The type 'AutofacNUnitLib.FakeService' is not assignable to service 'Autofac.IStartable'.
at Autofac.Builder.RegistrationBuilder.CreateRegistration(Guid id, RegistrationData data, IInstanceActivator activator, IResolvePipelineBuilder pipelineBuilder, Service[] services, IComponentRegistration target)
at Autofac.Builder.RegistrationBuilder.CreateRegistration[TLimit,TActivatorData,TSingleRegistrationStyle](IRegistrationBuilder`3 builder)
at Autofac.Builder.RegistrationBuilder.RegisterSingleComponent[TLimit,TActivatorData,TSingleRegistrationStyle](IComponentRegistryBuilder cr, IRegistrationBuilder`3 builder)
at Autofac.RegistrationExtensions.<>c__DisplayClass40_0.<RegisterType>b__0(IComponentRegistryBuilder cr)
at Autofac.ContainerBuilder.Build(IComponentRegistryBuilder componentRegistry, Boolean excludeDefaultModules)
at Autofac.ContainerBuilder.Build(ContainerBuildOptions options)
at AutofacNUnitTest.ServiceFactory.CreateContainer(String typeName, String interfaceName) in C:\dev\repos\AutofacNUnit\AutofacNUnitTest\ServiceFactory.cs:line 28
at AutofacNUnitTest.ServiceFactoryTests.FakeServiceDiffProjects() in C:\dev\repos\AutofacNUnit\AutofacNUnitTest\ServiceFactoryTests.cs:line 18
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
Run Settings
DisposeRunners: True
WorkDirectory: C:\dev\repos\AutofacNUnit\AutofacNUnitTest\bin\Debug\net7.0
ImageRuntimeVersion: 4.0.30319
ImageTargetFrameworkName: .NETCoreApp,Version=v7.0
ImageRequiresX86: False
ImageRequiresDefaultAppDomainAssemblyResolver: False
TargetRuntimeFramework: netcore-7.0
NumberOfTestWorkers: 8
Test Run Summary
Overall result: Failed
Test Count: 2, Passed: 1, Failed: 1, Warnings: 0, Inconclusive: 0, Skipped: 0
Failed Tests - Failures: 0, Errors: 1, Invalid: 0
Start time: 2023-07-28 06:34:26Z
End time: 2023-07-28 06:34:28Z
Duration: 2.661 seconds
Details on ServiceFactory: The intention is to register type and interface given by its fullname as string (read from a config). Owing to lazy loading of assemblies the assembly containing this type/interface may not be loaded and is not found by Type.GetType(). Therefore, I implemented the FindAssemblyInBin loading all dlls from the executing folder. This works. With my debugger I see that foundType and foundInterface are correct and implement the correct interfaces (if they are null, RegisterType() would fail anyway). In the printout of the foundType you also see that the type is correct and that Autofac.IStartable is implemented.
Removing As<IStartable> or reducing it even to builder.Registertype(foundType).SingleInstance() doesn't work, either. In this case, the Assert.IsTrue fails as it cannot resolve the type, though it is registered.