0

I'm writing a weather application and I've created a sort of weather model that does all the calculations, fetching of data, etc. Before I created the ViewControllers, I wanted to write some unit tests for my model to ensure that everything was working properly (the weather is being fetched in the expected format, weather is refreshing correctly, etc.).

Now I would love to unit test with confidence and test for equality like:

STAssertEquals([[testableModel weatherDictionary]objectForKey:@"current_conditions"], @"Sunny", @"The weather should be sunny.");

...but alas, mother nature changes so fast. Also, (and correct me on this), I don't think I can connect to the Internet while I'm unit testing(...?) (Either way, it doesn't particularly matter.)

So, I searched on my most favorite website and I found this question: how to unit test a NSURLConnection Delegate?

It was quite informative, but now I've got a question. When I call a method that invokes an NSURLConnection delegate method, such as:

[myBeautifulWeatherModel getTheWeather];

...how do I feed the model (i.e., myBeautifulWeatherModel, which is implementing the NSURLConnection delegate methods) data? The model is going to do some JSON parsing when it receives its data in this delegate method:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection;

My first thought was to take the JSON data that Wunderground sends back and just change some of the keys so that they match expected data and feed that in. But the question is HOW would I feed in that response?

I understand that NSURLConnection is going to call 3 required delegate methods. I feel like I need to "fake out" the following:

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;

But again, I'm a little confused as to how I feed it in and get this model to think its connected to the Internet.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Thanizer
  • 382
  • 1
  • 6
  • 21

1 Answers1

0

I think you're trying to test too broadly. What you want to test here are 2 things: 1) when the NSURLConnectionDelegate callbacks are invoked, they correctly write the data somewhere useful, and 2) given some stored data when the connection completes, it gets stored in your model appropriately. So something like this:

-(void)testShouldAppendData {
    expect([connectionDelegate data]).to.beNil();

    NSString *response = @"1";
    NSData *responseData = [input dataUsingEncoding:NSUTF8StringEncoding];
    [connectionDelegate connection:connection didReceiveData:responseData];

    NSString *stringFromResponseData = [[[NSString alloc] initWithData:[connectionDelegate data] encoding:NSUTF8StringEncoding] autorelease];
    expect(stringFromResponseData).to.equal(@"1");

    [connectionDelegate connection:connection didReceiveData:responseData];
    stringFromResponseData = [[[NSString alloc] initWithData:[connectionDelegate data] encoding:NSUTF8StringEncoding] autorelease];
    expect(stringFromResponseData).to.equal(@"11");
}

and for the data format:

-(void)testShouldUpdateWeatherModel {
    NSString *response = @"{\"current_conditions\":\"sunny\"}}";
    NSMutableData *responseBytes = [NSMutableData dataWithData:[response dataUsingEncoding:NSUTF8StringEncoding]];
    [connectionDelegate setData:responseBytes];

    [connectionDelegate connectionDidFinishLoading:nil];

    expect([[connectionDelegate weatherDictionary] objectForKey:@"current_conditions"]).to.equal(@"sunny");
}
Christopher Pickslay
  • 17,523
  • 6
  • 79
  • 92
  • Thanks for the response! But I do I have one question: when you say [handler connection:connection didRecieveData:responseData], which connection are you assuming is being used? The connection that is in "handler"? – Thanizer Jul 30 '12 at 21:47
  • I've updated `handler` to `connectionDelegate` in the sample tests. I mean the object that implements `NSURLConnectionDelegate`, which for simplicity I assumed is the same object that exposes a `weatherDictionary` property. – Christopher Pickslay Jul 30 '12 at 21:55
  • One way to approach this is to have a base class that implements the `NSURLConnectionDelegate` callbacks, and subclasses for each different type of connection (for example, one subclass per API method you call). In that setup, I'd put `testShouldAppendData` in a test class for the base class, and tests like `testShouldUpdateWeatherModel` in test classes for the subclasses. – Christopher Pickslay Jul 30 '12 at 21:57