ssannandeji / Zenject-2019

Dependency Injection Framework for Unity3D
MIT License
2.53k stars 363 forks source link

Testing Signal bindings #592

Open cpetry opened 5 years ago

cpetry commented 5 years ago

This is a question which originates from #551.

Is it also possible to use BindSignal instead of Subscribe ?
I would like to write a unit test that checks my bindings. Here is what I would like to do:

[Test]
public void Signal_SomeSignal_ShouldFireAllRelated()
{
  SignalBusInstaller.Install(Container);
  ProjectSignals.BindSignals(Container); // Binds all my signals for my project

  var someMock = new Mock<ISomeInterface>();
  Container.Bind<ISomeInterface>().FromInstance(someMock.Object);

  var target = Container.Resolve<SignalBus>();
  target.Fire<Signal_SomeSignal>();

  someMock .Verify(x => x.DoSomething(), Times.Exactly(1));
}

But this doesn't work. No Subscriptions.

svermeulen commented 5 years ago

I can't reproduce this. Can you provide a complete reproducible example? There are unit tests which use BindSignal which do work (eg. TestBindSignal.cs)

cpetry commented 5 years ago

Here a minimal example. I hope it's just me using it wrong:

public class FooSignal { }
public interface ISubscribeToSignal { void DoSomething(); }

[Test]
public void Signal_ShouldFireAllSubscribed()
{
    // Arrange
    SignalBusInstaller.Install(Container);
    Container.DeclareSignal<FooSignal>();
    Container.BindSignal<FooSignal>().ToMethod<ISubscribeToSignal>(x => x.DoSomething).FromResolve();

    var subscriberMock = new Mock<ISubscribeToSignal>();
    Container.Bind<ISubscribeToSignal>().FromInstance(subscriberMock.Object);

    var target = Container.Resolve<SignalBus>();

    // Act
    target.Fire<FooSignal>();
    Debug.Log(target.NumSubscribers);

    // Assert
    subscriberMock.Verify(x => x.DoSomething(), Times.Exactly(1));
}

Also the Debug.Log() returns "0"

atesbalci commented 5 years ago

Same here, I can't test the signals using BindSignal. (No subscribers on fire)

shadhex commented 5 years ago

Once you have your signaled binded, try calling Container.ResolveRoots(); Also make sure you don't have a [Setup] method that injects or resolves the signalbus.

[Test]
public void Signal_SomeSignal_ShouldFireAllRelated()
{
  SignalBusInstaller.Install(Container);
  ProjectSignals.BindSignals(Container); // Binds all my signals for my project

  var someMock = new Mock<ISomeInterface>();
  Container.Bind<ISomeInterface>().FromInstance(someMock.Object);
  Container.ResolveRoots(); //This guy

  var target = Container.Resolve<SignalBus>();
  target.Fire<Signal_SomeSignal>();

  someMock .Verify(x => x.DoSomething(), Times.Exactly(1));
}

In [Setup] you can call the installer there if you'd like


       //[Inject] SignalBus _signalBus = null;
        [SetUp]
        public void Install()
        {
           SignalBusInstaller.Install(Container);
            //do not inject _signalBus since you might be installing specific binding
            //in [test] later on.  Resolve<SignalBus> in invidual [test] instead.
           //Container.Inject(this);
        }

The example above were all doing this, but it will fail if SignalBus was also injected in [SetUp].

batrand commented 4 years ago

Was having the same issue where BindSignal does not get called in unit tests; dropping in to confirm that adding Container.ResolveRoots() solves the issue.