Enforcing that a class posts a particular NSNotification?
Asked Answered
C

1

0

Is there any way to ensure that a class posts a particular NSNotification?

(I have a set of classes, and I would like to enforce at compile-time (if possible) that the class posts a required NSNotification).

Alternatively, if that is not possible, is there any workaround?

Corned answered 30/6, 2009 at 7:17 Comment(0)
D
3

It's fundamentally impossible to predict at compile time what will happen at run time. The closest you can get is static analysis, but even that can't predict anything that happens outside of your own code, such as inside Foundation.

You can, however, do this with unit tests, since the test runner actually runs the code under test.

You'll need to create a test bundle target, if you haven't already. Your target will use SenTestingKit to run your tests, which you create. (On the iPhone, you'll also need Google Toolbox for, uh, Mac. They have a handy tutorial on using GTM for iPhone tests.)

You'll create a SenTestCase subclass to test whether your real object posts a notification. It'll look something like this:

@interface FrobnitzerNotificationsTest: SenTestCase
{
    BOOL frobnitzerDidCalibrate;
}

- (void) frobnitzerDidCalibrate:(NSNotification *)notification;

@end

@implementation FrobnitzerNotificationsTest

- (void) testFrobnitzerCalibratePostsNotification {
    Frobnitzer *frobnitzer = …;
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];

    [nc addObserver:self
        selector:@selector(frobnitzerDidCalibrate:)
        name:FrobnitzerDidCalibrate
        object:frobnitzer];

    frobnitzerDidCalibrate = NO;

    //This should post a notification named FrobnitzerDidCalibrate with the receiver as the object.
    [frobnitzer calibrate];
    //If it did, our notification handler set frobnitzerDidCalibrate to YES (see below).

    [nc removeObserver:self
        name:FrobnitzerDidCalibrate
        object:frobnitzer];

    STAssertTrue(frobnitzerDidCalibrate, @"Frobnitzer did not post a notification when we told it to calibrate");
}

- (void) frobnitzerDidCalibrate:(NSNotification *)notification {
    frobnitzerDidCalibrate = YES;
}

@end

You'll need one instance variable and one notification-handler method for every notification you want to test for, and one test method for every method you want to test for notifications.

Also, if using GTM, you must substitute GTMSenTestCase for SenTestCase above.

Doodlesack answered 30/6, 2009 at 7:52 Comment(2)
I dare say I'm missing something but Apple has several classes (NSView, ABPeoplePickerView) that promise to post notifications when a certain event takes place. I can't quite see how test cases will enforce that these notifications are posted, as requested by Nocturne.Aikoail
If the notification (or any other thing under test, such as drawing into an image before Snow Leopard) requires a window server connection to happen, then you won't be able to test it in the command-line tool provided by OCUnit. You'd need to implement something that runs the tests in an app. In the test case method, the code would be the same: Add observer, set instance variable to NO, cause the notification,( set the instance variable to YES in the notification method,) remove observer, assert that the instance variable is YES.Doodlesack

© 2022 - 2024 — McMap. All rights reserved.