hadashiA / VContainer

The extra fast, minimum code size, GC-free DI (Dependency Injection) library running on Unity Game Engine.
https://vcontainer.hadashikick.jp
MIT License
1.81k stars 157 forks source link

Bugs in Playmode tests #677

Closed hendrik-schulte closed 1 week ago

hendrik-schulte commented 1 month ago

I was playing around with a LifetimeScope in editmode and playmode tests and ran into an issue that seems like a bug to me. This is my setup:

public interface IFoo
{
    public string Name { get; }
}

public class Foo : IFoo, IDisposable
{
    public string Name => "Foo";

    private Foo()
    {
        Debug.Log("Foo Created");
    }

    public void Dispose()
    {
        Debug.Log("Foo Disposed");
    }
}

public class Root :
    IInitializable,
    IStartable,
    IDisposable
{
    public Root(IFoo dep)
    {
        Debug.Log("Root Created with " + dep.Name);
    }

    public void Initialize()
    {
        Debug.Log("Root Initialized");
    }

    public void Start()
    {
        Debug.Log("Root Started");
    }

    public void Dispose()
    {
        Debug.Log("Root Disposed");
    }
}

This is the test:

[Test]
public void VContainer()
{
    using var scope = LifetimeScope.Create(builder =>
    {
        builder.RegisterEntryPoint<Root>();

        builder
            .Register<Foo>(Lifetime.Scoped)
            .AsImplementedInterfaces();
    });

    scope.Build();

    Assert.That(scope.gameObject, Is.Not.Null);

    var foo = scope.Container.Resolve<IFoo>();

    Assert.That(foo, Is.Not.Null);
    Assert.That(foo, Is.TypeOf<Foo>());
    Assert.That(foo.Name, Is.EqualTo("Foo"));

    Object.DestroyImmediate(scope.gameObject);
}

The test passes and all callbacks work fine with the following output:

Foo Created
Root Created with Foo
Root Initialized
Foo Disposed
Root Disposed

Just as expected.

However, when I run the very same test as a playmode test, I get the following exception:

VContainer.VContainerException : No such registration of type: IFoo

Also, if I don't resolve IFoo and ommit the assertions, the dispose callbacks are not called:

Foo Created
Root Created with Foo
Root Initialized

Unity 2022.3.24f1 VContainer 1.15.4 Unity Test Framework 2.0.1-pre.18

hadashiA commented 1 week ago

When using LifetimeScope.Create, there is no need to call Build manually.

This line seems to be causing problems.

scope.Build();

It seems to actually call .Build() on the LifetimeScope base class.

( This is admittedly a bit odd. Maybe it should be an error, but it could be a breaking change..

Incidentally, you can write tests without using LifetimeScope (MonoBehaviour) by doing the following. For reference.

var builder = new ContainerBuilder();
builder.Register<Foo>(Lifetime.Scoped);
// ...
var container = builder.Build();