In my swift app, I have a view controller with several buttons. When the user interacts with these buttons, they trigger code that may have some dependencies. It can look something like this:
class ViewController: UIViewController {
@IBOutlet weak var button1: UIButton!
@IBAction func button1Down(sender: UIButton) {
// Do some stuff
SomeUtil().doSomething()
}
}
This is a major problem for testing. I'd like to test the interface for the view controller, IE the button1Down. This button1Down is coupled to a dependency that I would like to mock in a unit test. This implementation leaves no possibility of mocking.
Now, I've found two ways to do dependency injection, both with default parameters. I can (1) set the view controller up like this:
class ViewController: UIViewController {
@IBOutlet weak var button1: UIButton!
@IBAction func button1Down(sender: UIButton) {
// Do some stuff
somemethod()
}
func somemethod(util: SomeUtil = SomeUtil()) {
util.doSomething()
}
}
This works, but I'm not really testing the view controller's interface. I'm testing some implementation specific method to get around the fact that I can't add a default parameter to an overridden function.
I can (2) set the dependency injection up like this:
class ViewController: UIViewController {
@IBOutlet weak var button1: UIButton!
var util: SomeUtil!
@IBAction func button1Down(sender: UIButton) {
// Do some stuff
util.doSomething()
}
func injectDeps(util: SomeUtil = SomeUtil()) {
self.util = util
}
override func viewDidLoad() {
super.viewDidLoad()
injectDeps()
}
}
This method is great for utilities that I use in multiple methods, as it is reasonable to save the utility as an instance variable. This is not ideal for utilities that only get used in one method. These utility instances have no reason to be associated as a variable on the instance, other than to make testing easier.
As far as mocking goes, I usually just do something like this (using quick framework):
var viewController: MyApp.ViewController!
class SomeUtilMock: SomeUtil {
override func doSomething() {
// do something test specific
}
}
var someUtil: SomeUtilMock!
beforeEach {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
viewController =
storyboard.instantiateViewControllerWithIdentifier(
"MainView") as! MyApp.ViewController
someUtil = SomeUtilMock()
viewController.beginAppearanceTransition(true, animated: false)
viewController.endAppearanceTransition()
viewController.injectDeps(someUtil)
}
Has anyone found a better way to do dependency injection and mocking in swift? Neither of these dependency injection methods are ideal.
Thanks in advance!
Aucun commentaire:
Enregistrer un commentaire