In a previous post we showed how to test Singletons with Constructor Injection. This will show another technique using Property Injection. Property Injection is useful in cases where a custom init method isn’t practical. A useful case for this is testing ViewControllers created by a Storyboard.

So what’s the difference?

Instead of injecting the dependencies in our init method we make the property with the reference to the singleton public. The calling code can override the default implementation directly. We’re also required to make the property mutable (changeable) by declaring it as var.

public class AnotherViewController: UIViewController {

    public var scarySingleton = ScarySingleton.sharedInstance
        
    public func importantStuff() {
        // So testable!
        scarySingleton.doSomethingImportant()
        scarySingleton.someimportantValue = "So important!"
    }
}

And now the tests

class AnotherViewControllerTests: XCTestCase {
    
    var storyboard: UIStoryboard!
    var sut: AnotherViewController!
    var scaryStub: ScaryStub!

    class ScaryStub: ScarySingleton {
        var doSomethingImportantCalled: Bool = false
        
        override func doSomethingImportant() {
            doSomethingImportantCalled = true
        }
    }
    
    override func setUp() {
        super.setUp()
        storyboard = UIStoryboard(name: "Main", bundle: nil)
        sut = storyboard.instantiateViewControllerWithIdentifier("AnotherViewController") as? AnotherViewController
        scaryStub = ScaryStub()
        // we inject our dependency here
        sut.scarySingleton = scaryStub
        sut.importantStuff()
    }
 
    func testDoSomethingImportantIsCalled() {
        XCTAssertTrue(scaryStub.doSomethingImportantCalled)
    }
    
    func testImportantValueIsSet() {
        XCTAssertEqual(scaryStub.someimportantValue!, "So important!")
    }
}

When should I use Property Injection?

Constructor Injection should be the default when you have control over the init methods. If you don’t have that control, Property Injection is a less pristine, but perfectly acceptable, alternative. To use any kind of DI container in Objective-C we are forced to use Property Injection anyways. We’ve somehow survived.

Purist Gripes:

  • Our dependency is both public and var (mutable). Any code can get into our business and mess things up.
  • Property Injection is easier to get wrong. It’s easy to miss setting a new dependency, especially when adding a new one. The compiler catches these mistakes when using Constructor Injection.

Pragmatic Pluses:

  • We don’t have to adapt the rest of our application just to test our singletons.

Leave a Reply

Your email address will not be published. Required fields are marked *