JasperFx / lamar

Fast Inversion of Control Tool and Successor to StructureMap
https://jasperfx.github.io/lamar
MIT License
568 stars 119 forks source link

Issue using Lamar with ASP Net Core Integration Tests #199

Closed StuartFergusonVme closed 4 years ago

StuartFergusonVme commented 4 years ago

I currently have an ASP Net Core 2.2 REST API with I am in the process of converting to ASP Net Core 3.0.

This has forced me to move over from using Structure Map to Lemar which I have no problem with, however since the move I have been unable to run my Integration Tests which were written following this MS article (https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-3.0).

I am assuming the issue is the WebApplicationFactory is overwriting the registrations using ConfigureServices which is no longer used by the Lemar plugin. This means my tests are not using the mocked versions of the dependencies but the real versions.

Has anyone else come across this issue and if so do you have a workaround/solution to the issue I am experiencing.

hahn-kev commented 4 years ago

I'm also having this issue. So far the only way I've been able to override dependencies is by specifying that they're injectable and then using nested containers to inject the mocked version.

However that doesn't scale very well because you still can't override registrations on a per test basis. I've spent the last few hours trying to figure this out but I've got nothing.

Sadly you also can't do this:

var conatiner = host.Services.GetService<IContainer>();
conatiner.Configure(...);

because configure is only addative at this point. I'm considering switching to another IoC conatiner because it seems like there's no support for overriding dependencies properly and so we need to hack around trying to find the correct place to register our changes.

jeremydmiller commented 4 years ago

@hahn-kev @StuartFergusonVme I realize that this is a weakness of Lamar, but the kind of runtime flexibility that StructureMap had for overwriting dependencies also directly contributed to it being slow and having very complicated internals. If this is a deal breaker, I say you move over to another container.

@StuartFergusonVme I'm not familiar with the approach in that article. You'd have to provide a little more information about how you're bootstrapping things. It could be that you're getting nailed by the registration order, which Lamar respects and StructureMap actually didn't with the Add v. Use dichotomy. Remember that the last registration wins. You might be getting hit with the fact that the Startup registrations go last no matter what.

It might be necessary to give Lamar some kind of way to say "no, these registrations go last no matter what".

StuartFergusonVme commented 4 years ago

Yeah @jeremydmiller seems like its down to the ordering of the registrations.

I commented out the registration from my actual startup file and I now get the Mock registration that my test expects.

It might be necessary to give Lamar some kind of way to say "no, these registrations go last no matter what".

That sounds like it would be perfect for this use case

jeremydmiller commented 4 years ago

I'm closing this one after the last comment from @StuartFergusonVme

DrMueller commented 3 years ago

@jeremydmiller I've stumbled over this thread, as I have exactly the same problem. From what I understand, the configuration of Lamar (i.e. calling the ServiceRegistries) comes after everything. The steps are executed in this order:

  1. WebApplicationFactory.ConfigureWebHost
  2. Startup.ConfigureServices
  3. builder.ConfigureServices
  4. builder.ConfigureTestServices
  5. Startup.ConfigureContainer (Container still not configured) ???
  6. ServiceRegistries are called and the Container set

Unfortunately, I couldn't find the exact point, where the Container-setup is wrapped up. Also, there seems no hook, in which I can overwrite any services. Isn't the issue, that ConfigureContainer is called after ConfigureTestServices? From what I understand, ConfigureTestServices is the Microsoft approach to overwrite the services, which would perfectly fit the bill.

From what I've understood from @StuartFergusonVme solution, he's not using ServiceRegistries?

I really love Lamar, but I also love integration-testing. Is there any hope there might come something?

jeremydmiller commented 3 years ago

@DrMueller I still don't think there's anything to do in Lamar. If it was me, I'd take advantage of conditional registrations based on the IHostingEnvironment inside of the Startup.ConfigureContainer to dodge the ordering issue. This might be worth a blog post some day on ways to do this, but I don't think there's anything development wise to do.

DrMueller commented 3 years ago

@jeremydmiller Thank you for the quick feedback. Could you add 1-2 sentences, what you mean exactly? I see your approach working if I register services directly, but I have some sort of ports and adapters architecture, in which every layer uses a ServiceRegistry and the configuration is just a call to LookForRegistries. Therefore, the ConfigureContainer doesn't know, which services are registered.

twinter-amosfivesix commented 3 years ago

This may not be the exact situation the others are having, but in case it helps anyone in the future...I was having similar sounding problems using WebApplicationFactory and it's ConfigureTestServices method to mock out a specific service. Lamar's scanning done in ConfigureContainer was "overwriting" what I was registering in ConfigureTestServices. I was using .WithDefaultConventions() for the scan. I switched that to .WithDefaultConventions(OverwriteBehavior.Never) and things started working.

https://jasperfx.github.io/lamar/documentation/ioc/registration/auto-registration-and-conventions/

OverwriteBehavior.Never: Do not add any registrations if the ServiceType is already registered. This will prevent the scanning from overwriting existing default registrations