hmlongco / Factory

A new approach to Container-Based Dependency Injection for Swift and SwiftUI.
MIT License
1.71k stars 107 forks source link

Mocking does not work for the `singleton` scope #96

Closed VladimirAmiorkov closed 1 year ago

VladimirAmiorkov commented 1 year ago

Hi, Thanks for all of the work you have been doing with this project. Its very easy to work with and I have not faced any issues I was not able to resolve. But today after upgrading to 2.x.x I am having an issue with my unit tests and mocking singletons.

In version 1.x.x I was making mocks of my singleton declarations by:

  1. Inside setUpWithError I would call Container.Registrations.push()
  2. Register a new factory of my mock instance
  3. Finally inside tearDownWithError I would call Container.Registrations.pop().

This way my singleton DI would be correctly replaced by my mock instances.

Now I switch to latest version (2.1.x) and I am doing the following:

If I have:

extension Container {
    var myString: Factory<String> { Factory(self) { "Initial string" }.singleton }
}
  1. Inside setUpWithError I create a new Container.shared instance Container.shared = Container()
  2. Register a new factory of my mock instance: Container.shared.myString.scope(.singleton).register { "New string" }

(also tried with Container.shared.testService.register { "New string" }

But after this mock/change if I call Container.shared.myString.callAsFunction() it gives Initial string

I used String to simply the example but the same behavior is observed with any type of object.

I have checked the docs and I see in the mocks section there is:

extension Container {
    static var myService: MyServiceType { MyService() }
}

...
let _ = Container.myService.register { MockService2() }

But the line Container.myService.register does not compile as there is no register on the MyService. In that example myService is just a static var of a type. Or is this custom code that needs to be written, if yes what should it do?

If I make this into a not singleton by removing the .singleton, then all works as expected.

Am I doing something wrong here? Thanks.

hmlongco commented 1 year ago

I think most of this is addressed in 2.1.3. Pushing/popping containers has no effect on singletons, their scope is outside that of a single container.

That said, registering a change on a singleton Factory works as it did before, the assumption being that if you registered it you're expecting it to be used.

See the Testing Singletons section in Testing for more.

VladimirAmiorkov commented 1 year ago

Thank you very much.