Method code like so:
- (void)downloadSomething:(NSString *)url {
Downloader *downloader = [[Downloader alloc] initWithUrl:url];
NSData *data = [downloader download];
FileCache *cache = [[FileCache alloc] initWithFile:@"download.cache"];
cache.data = data;
[cache save];
}
I think I should mock Downloader and FileCache to verify if it works well.
I have thought about change signature like that: downloadSomething:(NSString *)url downloader:(Downloader *)downloader cache:(FileCache *)cache
, but it seem to have to do much work before call this methods, that's not what I want.
I am using ocmockito.
Besides, is there a guide to make writing code more testable ?
edit: 2017-01-16 14:54:23
Is this a good idea to write two method like:
- (void)updateCacheWithUrl:(NSString *)url
downloader:(Downloader *)downloader
fileCache:(FileCache *)fileCache; // for testing
- (void)updateCacheWithUrl:(NSString *)url; // call above method with (url, nil, nil);
When a collaborator is instantiated inside a method, this creates tight coupling. The difficulty of testing this leads us to explore other designs.
One way is to pass them in. This is what I'd normally do. Then I would make a simpler version that provides default objects for production code.
But in your example, the url
is passed to the Downloader
, which makes this harder. This suggests that the current design of downloadSomething:
violates the Single Responsibility Principle. It's doing two things: downloading, and caching.
So splitting up these responsibilities would probably make things easier to test.