JasperFx / lamar

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

Allow Inject without Injectable<> for use in testing #111

Closed henrik-mvno closed 5 years ago

henrik-mvno commented 5 years ago

Hi :)

From reading the documentation I understand that the current implementation of Contain.Inject requires you to first call Injectable<> in your registry. This is a departure from Lamar's predecessor StructureMap which allowed you to inject any type at runtime without prior configuration.

I have relied on this flexibility in StructureMap to do "Acceptance" or blackbox testing of large systemets in the past. The basic idea is that I want to start with the production configuration of the system, and the inject mocks for all the external dependencies (so I can control data flow and assert on results).

A greatly simplified example:

public class ProductionRegistry : ServiceRegistry
{
    public ProductionRegistry()
    {
        For<ISomeType>().Use<SomeType>();
    }
}

[Fact]
public void Should_inject_mock_at_runtime()
{
    var mock = Substitute.For<ISomeType>();
    var container = new Container(new ProductionRegistry());
    container.Inject(mock);

    var result = container.GetInstance<ISomeType>();

    result.Should().Be(mock); //fail
}

With the current implementation of Lamar this is not possible without substantial changes to ProductionRegistry as I basically have to add an Injectable<> call for every type that needs to be replaced in some test. This seems wrong to me on two fronts:

Would it be possible to get back some mechanism to support this functionality again?

jeremydmiller commented 5 years ago

"This is a departure from Lamar's predecessor StructureMap which allowed you to inject any type at runtime without prior configuration." -- and a massive headache for the SM internals and performance that I refuse to support this time around. When you stand up your application at test time, you can still override individual services.

Something like:

var registry = new ProductionRegistry();

registry.AddSingleton<ISomething>(Substitute.For<ISomething>());

var container = new Container(registry);
henrik-mvno commented 5 years ago

Hmm, back to the drawing table then I suppose :)

henrik-mvno commented 5 years ago

It works, thanks for the input :)