HHuckebein / BrowseOverflow

BrowseOverflow using OCHamcrest/OCMockito

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

BrowseOverflow using OCHamcrest/OCMockito

I recently came to Graham Lee’s book Test-Driven iOS Development when looking when searching for an in-depth look on unit testing.
Graham’s Book doesn’t make use of mock objects but using what is coming with every Xcode installation – OCUnit.

The unit testing environment lacks mock object, so as soon as you start to dive into test driven development you have to choose your tools.
I’ve decided to start with John Reid’s OCHamcrest/OCMockito and though I found it sometimes difficult to achieve what I needed, I finally was able to work through the books example without greater problems.
I even found a rather bad coding style on my side. So thinking about testing in the first place makes you more thinking about your design and coding style in the first place too.

If you haven’t done unit testing before I strongly recommend the excellent screen casts John made on http://www.qualitycoding.org.

What has changed

In short – especially using OCHamcrest/OCMockito made the test code shorter and therefor easier to read.
You will see that the project uses storyboarding and more often property declarations and the automatic synthesize behavior. So I even deleted some of the tests where only setter behavior was tested (e.g. testAnswerHasSomeText in AnswerTest.m).
Here are the other things I changed

Provider vs. DataSource/Delegate

When you work through the book you see that Graham developed a dataSource and delegate class and then merged the delegate methods into the dataSource class. The class is called ..DataSource.h/.m which I find isn’t ideal.
So the classes, as we need several provider, are all named following that naming convention (TopicTableDataSource → TopicTableProvider).

BrowseOverflowDelegate Protocol

Instead of Graham’s BrowseOverflowObjectConfiguration class I moved the code into the AppDelegate and created a protocol to have access to the StackOverflowManager, the AvatarStore and the initial topics array.

Moving methods

I reduced the number of classes a bit moving methods into other classes.
You wont find an AnswerBuilder class as the only method


	- (BOOL)addAnswersToQuestion:(Question *)question fromJSON: (NSString *)objectNotation error: (NSError **)error;

seemed to me better placed into the Question class as


	- (BOOL)addAnswersFromJSON: (NSString *)objectNotation error: (NSError **)error;

The same happened to


	- (void)fillInDetailsForQuestion: (Question *)question fromJSON: (NSString *)objectNotation;

from QuestionBuilder class, which I renamed to


	- (void)fillInDetailsFromJSON: (NSString *)objectNotation;

thus removing some test as well.

Performing actions on private methods

For testing purposes you sometimes need to have access to an otherwise private method or instance variable and you feel uncomfortable for exposing it.
Well, you can always use


	[Object valueForKey:key]

or


	[Object performSelector:withObject];

Added Methods

I wrote for most of the classes a description method, so that you can easily log things. I also used methods to display localized content for numbers as the recommended ways. This is also an interesting point when you unit test your user interface.

Where to go from here

As Graham pointed out on page 199 the app doesn’t work as one might expect. If you browse the same topic twice you find the same questions added again to the recentQuestions list.
At least this problem can be easily solved by adding only questions to the recentQuestions array if they are not already part of it by examining the questionID.

I extended the QuestionTest class by three additional test


	- (void)testCompareForQuestionsWithIdenticalQuestionIDReturnsNSOrderedSame
	- (void)testCompareForQuestionsWithDifferentQuestionIDsReturnNSOrderesAscending
	- (void)testCompareForQuestionsWithDifferentQuestionIDsReturnNSOrderedDescending

plus extending the Question class with a compare method


	- (NSComparisonResult)compare:(Question *)question
	{
		NSComparisonResult result = NSOrderedAscending;
		if (self.questionID == question.questionID) {
			result = NSOrderedSame;
		}
		else if (self.questionID > question.questionID) {
			result = NSOrderedDescending;
		}
		
		return  result;
	}

and the Topic class with a method which returns TRUE if a question with a given questionID can be found in the current list.


	- (BOOL)containsQuestion:(Question *)question
	{
		NSUInteger index = [self.recentQuestions indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
			return [(Question *)obj compare:question] == NSOrderedSame;
		}];
	
		if (index == NSNotFound) {
			return FALSE;
		}
		else {
			return TRUE;
		}
	}

So before adding a new question to the list we can check if it is already part of the current list and skip adding if it is.

Another point is that the app starts networking tasks to fetch the content for the table views. Here we have only the 20 most recent questions but it is worse thinking about how to stop an ongoing task when the user leaves that view or scrolls the table view cell away from the visible screen area.

Miscelleanous

If you follow the books example page by page and write your tests and code together you might think that it takes a while before you see the app in action and you are right.
In agile development one would define a User Stories e.g. When the app starts it should show a list of topics.
As Jonathan Rasmusson in his book The Agile Samurai has put it, the user story shoud comply to INVEST (Independable, Negotiable, Valuable, Estimatable, Small, Testable).
For the BrowseOverflow app you could think of one user story to show the list of topics. And than the Questions for a specific topic.
If you try to group your test code around one user story you not only have a success when running your unit test but you could show also that you managed to code a running app.
Most likely you would have noticed that selecting a topic twice leads to adding the same questions again.

Acknowledgments

I read the book from Graham Lee and saw the screen casts for John Reid which gave me a lot of input to improve my skills – thanks for your awesome work.

About

BrowseOverflow using OCHamcrest/OCMockito


Languages

Language:Objective-C 100.0%