I am going to design a MVC pattern. It could be either designed as a delegate pattern, or a Key-Value-Observing(KVO), to notify the controller about changing models. The project requires certain quality control procedures to conform to those verification documents.
My questions:
-
Does delegate pattern fit better for unit testing than KVO?
-
If KVO fits better, would you please suggest some sample codes?
0
I think this is the wrong question. Delegates, KVO, and notifications can all be unit-tested. That should not be the primary concern when picking how objects interact with each other.
Pick the pattern that is appropriate for the problem you are trying to solve. For example, Apple uses delegates to allow a UITableView to pull information from a controller. This feels appropriate. The table view knows what information it needs and pulls that information out of its delegates.
Apple could have chosen to have UITableView send notifications. There is no technical reason why a table view doesn’t send a UITableViewCellForRowAtIndexPathNotification and expect a subscriber to set the cell at an index path included in the user info. They didn’t do this because it’s not appropriate.
Generally speaking, delegates are appropriate for pulling information from a source of truth. Views use this to gather details needed for display. Notification and KVO are appropriate pushing information out from a source of truth. Models use this to announce changes which the rest of the system may need to know about.
UPDATE
After reading your question again, it seems like you want to use KVO. As for code a unit test, here is some code to demonstrate how this can be done.
I assume you are looking to test a controller which is observing a change to a property of a model. When the change is observed, the controller will change the text of a view. Controller will have a properties named model and textView. Model will have a property name prop. TextView will have a property named text. The controller does KVO by calling [self addObserver:self forKeyPath:@"model.prop" options:0 context:NULL]
.
FakeModel *fakeModel = [[FakeModel alloc] init]; // FakeModel stubs out the needed functionality of Model.
FakeTextView *fakeTextView = [[FakeTextView alloc] init]; // FakeTextView stubs out the needed functionality of TextView.
Controller *controller = [storyboard instantiateViewControllerWithIdentifier:@"controller"]; // Or however you create your controller.
controller.textView = fakeTextView;
controller.model = fakeModel;
fakeModel.prop = @"new value"; // Change model.prop to kick off the KVO and change textview.text.
STAssertEqualObjects(fakeTextView.text, @"expected new text", @"Text should have matched");
Of course, you can use OCMock for this, if you have it in your project.
Hope that helps.
The delegate approach is easier to unit test because the delegate can be mocked and that mock used without needing to change (or performance heroics) in the original code.
1
Neither of your suggested approaches “fits better for unit testing”. You could use a delegate, KVO, a callback block, notifications or some other scheme—any of these things could be tested.
The key to writing testable code in my experience is to write the tests first, as with Test-Driven Development and its red-green-refactor mantra. That way, you are constrained to write code that can be (easily) tested by the fact that the test already exists and you need to write code that integrates with it.
If you write the code first, then try to test it, you have the same problem as with any attempt to integrate existing code—albeit on a small scale. You have to work out where your test needs to interface with the class, then whether the class supplies that interface, then whether the class expects the interface to be used that way…a major aspect of TDD is that you write the interfaces you need when you need them, rather than trying to retrofit them.