3

In the current Cocoa app I'm working on, I've got an object, RecordScheduler, which responds to two types of notifications, "day did pass" and "quicksaving interval did pass". In both cases, the RecordScheduler tells a Recorder to do its recording job, among other things.

Now I want RecordScheduler to issue a recording when the Mac goes to sleep.

You subscribe to sleep/wake notifications via NSWorkspace:

[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self 
        selector:@selector(computerWillSleep:) 
        name:NSWorkspaceWillSleepNotification object:nil];

This is easy enough. Add it to RecordScheduler's -init and the notifications would be processed just nicely.

Thing is, for the other two cases I wrote helper methods like fireDayDidPass() to use in unit tests. I fired my custom notifications and added assertions for RecordScheduler's response. Works well. I don't feel comfortable firing a NSWorkspaceWillSleepNotification since (a) it's not my own, and (b) I don't know about any side effects.

Instead, I resorted to calling [scheduler computerWillSleep:nil] which would receive notifications. Now I don't have an intergration-ish test to verify RecordScheduler subscribes to NSWorkspaceWillSleepNotification.

After I found out there is no additional information to be sent, I abandoned the idea of creating a HibernationObserver which subscribes to NSWorkspace's notifications and re-sends my own kind of "Will Sleep" and "Did Wake" notifications. There seemed to be no additional benefit.

Now here's the point:

  • Is it still a unit test when I fire a notification and assert for both the side effects of notification handling and the receiver's subscription upon initialization?
  • How else could I verify an object signs up itself as a notification receiver?
  • Should I make it a habit to wrap system notifications in my own?
1

Without going to formal definitions unit test should test a software unit (==>method). This is the lowest system test you perform.

Unit test should be light as possible and test the system from the unit perspective and you should not create any wrappers or test any system dependencies. doing so would create objects that are not part of your unit logic and the test shifts to wider aspects under unit test definition.

The solution of your problem is to create another testing layer (let's call it "component tests") in this test you need to test the integration between different system components. This would give you the ability to test the application in wider context and aspect, test the behavior of other objects etc.

This testing type can still use the same test framework you use for unit tests. At the component testing I do not think you should create dedicated test objects because of the overhead of the maintenance.

Creating dedicated object are basically the first steps of creating auto test framework and you should invest on it when testing the application context and above (application ==> system ==> network ==> eco-system ...).

In order to understand where each test belong to ask yourself questions about the context needed to run the test. This is in general:

  • Object context ==> unit test (verification)
  • Several objects context ==> component test (verification)
  • Application context ==> application tests (Validation)
  • Several applications context ==> System tests (validation)
  • client-server context ==> advanced system tests (validation)
  • Eco-System ==> Advanced system tests (Validation)

Each context has its own characteristics. You need to analyze each of which and create a mix for the best ROI.

Either way do I do not recommend you to invest much on the verification tests - any of the exist unit test frameworks should answer much of your needs - you just need to get familiar with it.

  • Thanks for the elaboration! Using an NSNotificationCenter falls under the category of "component tests." Alright, that makes sense, thank you. What's your approach to interacting with standard API objects, like Cocoa's centralized notification centers? – ctietze Jan 30 '14 at 17:10
  • This is matter of point of view. Standard API object usage should not be found in unit test, but can be found in component tests. and probably be quite common on application tests. – Saturn Technologies Jan 30 '14 at 22:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.