0

I am trying to learn unit tests. Following is my first ever written unit test for comparing string returned from the server. I am sure it's not perfect the way I handled the internet connection's availability and nsnotification. Test testGetURLEncodedString always printed pass as there is no assert statement in it. I can't put assert there as I have to compare the returned result from the server after response is received. Could anyone please suggest me to correct way of doing this please.

#import "MyAppTests.h"

@interface MyAppTests()
    @property(nonatomic) AppDelegate *delegate;
@end

@implementation MyAppTests

@synthesize delegate = _delegate;

- (void)setUp
{
    [super setUp];

    self.delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    if(![self.delegate internetConnectionAvailable])
    {
      STFail(@"Internet is not reachable.");
      exit(-1);
    }
}

- (void)tearDown
{
    _delegate = nil;
     [super tearDown];
}

- (void)testDelegate
{
     STAssertNotNil(self.delegate, @"Cannot find the application delegate");
}

- (void)testGetURLEncodedString
{
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getURLEncodedStringSuccess:) name:@"getURLEncodedStringSuccess" object:nil];
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getURLEncodedStringFailed:) name:@"getURLEncodedStringFailed" object:nil];

    [self.delegate getURLEncodedString:@"Testing Text"];
}

-(void)getURLEncodedStringSuccess:(NSNotification *)notification
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"getURLEncodedStringSuccess" object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"getURLEncodedStringFailed" object:nil];

    STAssertTrue([[self.delegate getURLEncodedStringResponse] isEqualToString:@"Testing Text"], @"testGetURLEncodedString failed - did not receive expected response");
 }

-(void)getURLEncodedStringFailed:(NSNotification *)notification
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"getURLEncodedStringSuccess" object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"getURLEncodedStringFailed" object:nil];

    STFail(@"testGetURLEncodedString failed - server failed returning result");
}
Filburt
  • 17,626
  • 12
  • 64
  • 115
Paresh Masani
  • 7,474
  • 12
  • 73
  • 139
  • That's not a unit test. It may be a whole-system test. Unit test would be testing (in separate tests) whether the right request is generated, contains the right values, is correctly passed on to the networking library. And then you can have a few, or even a few dozen, tests for the server code. Of course, separate tests for the request acceptance, the dispatching to some other code, and all the layers involved in the code creating the actual response. –  Aug 05 '12 at 22:02
  • Thanks @delnan I will need to read some books on unit tests I guess! – Paresh Masani Aug 06 '12 at 09:58
  • I noticed that I never get notification fired for testGetURLEncodedString. How would I exactly test whether server has returned expected response? – Paresh Masani Aug 06 '12 at 10:12

1 Answers1

0

Automated tests that call a server and check the response are better called "acceptance tests" of the server. But they should be kept in a separate target from the an app's unit test target, because unit tests need to be blazingly fast. And the main way to keep them fast is to avoid any real networking. And that's getting a little advanced.

Since you're just getting started with OCUnit, I suggest you not start with acceptance tests, because they're typically harder to write and provide less precise feedback. Instead, begin with the simplest tests which are tests of your model logic. My Xcode TDD 101 may be helpful for learning the mechanics of unit testing.

Jon Reid
  • 20,545
  • 2
  • 64
  • 95
  • Thanks for the info Jon. So where to write acceptance tests? Isn't they go in OCUnit testing project? Thanks. – Paresh Masani Aug 16 '12 at 09:59
  • Your Bowling Game Kata project details look really good. Thanks for that. – Paresh Masani Aug 16 '12 at 10:10
  • Acceptance tests where you use your app as the engine to test the server can still go in your project. But put them into a second test target (I call mine "ServerTests"). – Jon Reid Aug 16 '12 at 17:35
  • Okay. That makes sense. If you consider testGetURLEncodedString acceptance test, is it correct way to do it? The thing is I don't get any notification raised by delegate's getURLEncodedString method because before it gets it, test gets passed successfully!! I am really confused how to handle this situation. – Paresh Masani Aug 17 '12 at 08:21
  • No, the test doesn't make sense to me the way it's written -- it doesn't follow normal idioms. Shoot me an email at jon@qualitycoding.org and I'll try to help you offline. – Jon Reid Aug 17 '12 at 19:35
  • Thank you very much Jon. I have sent you my project that has this test. Please have a look and let me know to handle tests correct way. I will update here with my understandings. Thanks. – Paresh Masani Aug 18 '12 at 10:19