In our iPhone app unit tests we have one test suite which contains all test case classes. In the suite's setUp/tearDown we do general set up/tear down which creates/deletes some entities in DB. In setUp we use NSAsserts to asserts everything went right.
The problem is that if something goes wrong in setUp, NSAssert causes crash and tearDown is not being called, leaving the DB uncleaned.
What is the best way to make sure tearDown is always being called so the DB is always clean? Maybe not to use NSAsserts? But then how to tell the testing framework to not run test cases?
Thanks.
I'll suggest you add a boolean ivar to your test suite which is set in setUp when everything is setup correctly. The NSAssert is then replaced with setting this variable, eg. flagged by STAssert... in case anything goes wrong so it will cause your test to fail.
In each test case you then check that this ivar is true before performing the checks, e.g. by using something like this:
-(void)setUp {
// Perform the setup of the testbed and setting testBedStable accordingly
STAssertTrue(testBedStable, #"Failed to setup test environment";
}
-(void)testSomething {
if(testBedStable) {
// Perform tests
}
else
STFail(#"Unable to perform test case");
}
This method will ensure tearDown is always called and you can clean up accordingly.
Right, don't use NSAssert. Instead:
Pull database setup into separate helper methods.
Set instance variables to indicate what was successfully set up.
STFail on anything that isn't successfully set up.
Have each test call the appropriate helper methods.
In -tearDown, check the instance variables to see what needs to be cleaned up.
Example:
#interface DatabaseTest : SenTestCase
{
BOOL removeTestDataInTearDown;
}
- (void)addTestDataToDatabase
{
BOOL success;
// Attempt to add data to database. Set success according to results.
if (!success)
STFail(#"Unable to add test data to database", nil);
removeTestDataInTearDown = YES;
}
- (void)removeTestDataFromDatabase
{
// Remove data from database.
}
- (void)tearDown
{
if (removeTestDataInTearDown)
[self removeTestDataFromDatabase];
[super tearDown];
}
- (void)testSomething
{
[self addTestDataToDatabase];
// Execute test using data.
}
Note that even this has the potential to leave cruft in the database, which makes such tests fragile. So you might complement such tests with a different set of tests that uses mock objects in place of real database calls.
Related
In unit test case I try to make some own logic for my app, like register from another username at current or connect to different servers, without duplicate existing code.
First step that i try to make is a create XCTestCase, alloc class which support for external connections and try to get delegate calls from him.
But NSURLConnection just waiting without network exchange, so i was not success.
Next case, which i try to do is waiting while app will be done and do all issues then:
- (BOOL)waitForCompletion:(NSTimeInterval)timeInterval {
NSDate *timeoutDate =
[NSDate dateWithTimeIntervalSinceNow:timeInterval];
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:timeoutDate];
if([timeoutDate timeIntervalSinceNow] < 0.0) {
break;
}
} while (self.hasOperationFinishedPerforming == NO);
return self.hasOperationFinishedPerforming;
}
But in that case, app starting, do all current cycle, but i have no idea, how i can detect from current app code that there is running unit tests. I tried to set preprocessor macros on unit test target's but it not effected in code inside app, only effect on code of tests classes as well.
Any ideas?
Assuming you have set your unit test target's Bundle Loader build setting to use your app, you can determine if your app is running as part your unit tests like so:
static BOOL isRunningTests(void)
{
NSDictionary* environment = [[NSProcessInfo processInfo] environment];
NSString* injectBundle = environment[#"XCInjectBundle"];
return [[injectBundle pathExtension] isEqualToString:#"octest"]; // For SenTestKit; use "xctest" for XCTest
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if (isRunningTests())
return YES;
// Normal app launch stuff here...
...
}
That being said, your unit tests should not be testing anything that relies on external services, like APIs or databases, being available. If you cannot avoid having those kinds of things available, then you should look at "mock" objects (using 3rd party libraries like OCMock) which let you stub out complex classes and control what they return within your test environment.
The purpose of unit testing is NOT to test someone else's API or database or SDK, but rather to test your code and algorithms. If you can't test your code this way, that may be a signal that you need to refactor your code into more testable chunks.
There is a great book titled "Test-Driven iOS Development" by Graham Lee which I highly recommend that talks all about writing unit tests for iOS projects.
When you try to test a NSURLConnection which implements delegates, you need to take care to correctly implement the run loop related code.
Your waitForCompletion: method will likely not work or be unreliable. The reason is, method runMode:beforeDate: will not return until after an "event" has been executed in mode :NSDefaultRunLoopMode - or the timeout is expired. An event originates from some "run loop source" and ends up being a method which gets called. The NSURLConnection for example is such a "run loop source" since it schedules delegate methods which are "events" that get eventually executed by the target run loop for the specified mode.
Now, you loop until self.hasOperationFinishedPerforming == NO. The flag may be eventually set, and you may expect the run loop will return and check the flag. But this is not the case until after some arbitrary event has been scheduled afterwards to the run loop with the specified mode. Only then (unless expired), the runMode:beforeDate: returns and finally checks the flag.
In order to cause the run loop return immediately, you may send a dummy event in your completion handler, or wherever it's appropriate when signaling an asynchronous completion:
self.hasOperationFinishedPerforming == YES;
[#"" performSelector:#selector(self) onThread:thread
withObject:nil
waitUntilDone:NO];
This however, WILL indeed require the completion handler to know that it will execute in the testing environment.
There are solutions to avoid this completely, but will require third party libs.
My program works perfectly. I assure you with my life, 0 bugs. Proudly, I tried to package the application as an .ipa file for ad-hoc distribution to my beta tester using TestFlight.
The program didn't work. Animations which are supposed to happen never happened. Network code breaks. The button to fade out the music beautifully didn't do anything at all.
It turns out that the culprit is the new and shiny blocks. When I test my program in the Simulator or on my device, I used the default "Debug" build configuration. But when I archive it for distribution (and I believe later for submission to the App Store), XCode uses another configuration which is "Release". Investigating further, the difference is due to the optimization level (you can find it on XCode's Build Settings): Debug uses None (-O0) but Release uses Fastest, Smallest (-Os). Little did I know, that it's Fastest, Smallest, and Doesn't Work (tm). Yes, blocks behave differently between those 2 configurations.
So, I set out to solve the problem. I've simplified my soon-to-change-the-world app into its bare bones, shown in the image I've attached to this post. The view controller has an instance variable x with initial value 0. If we press b, it will spawn a thread that will continuously check the value of x, changing the bottom label when x becomes 1. We can change the value of x using button a.
Here is my naive code (I'm using ARC btw):
#implementation MBIViewController
{
int _x;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_x = 0;
}
- (void)updateLabel
{
self.topLabel.text = [NSString stringWithFormat:#"x: %d", _x];
}
- (IBAction)buttonAPressed:(id)sender {
_x = 1;
[self updateLabel];
}
- (IBAction)buttonBPressed:(id)sender {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (_x != 1) {
// keep observing for value change
}
dispatch_async(dispatch_get_main_queue(), ^{
self.bottomLabel.text = #"b changed me becase x changed!";
});
});
}
#end
_x is an instance variable, so it is reasonable to think that the block will access it using a pointer to "self", not on a local copy. And it works on the debug configuration!
But it doesn't work on Release build. So perhaps the block is using a local copy after all? OK, so let's explicitly use self:
while (self->_x != 1) {
// keep observing for value change
}
Doesn't work either in Release. OK, so let's access the damn variable directly using pointer:
int *pointerToX = &_x;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (*pointerToX != 1) {
// keep observing for value change
}
// other codes
});
Still doesn't work. This is when it dawned to me that the smart optimizing compiler assumes that there is no possible way in this multithreaded world that the result of the comparison will change, so perhaps it substituted it to be always TRUE or some other voodoo.
Now, when I use this, things start working again:
while (_x != 1) {
// keep observing for value change
NSLog(#"%d", _x);
}
So, to bypass the compiler optimizing out the comparison, I resorted to making a getter:
- (int)x
{
return _x;
}
And then checking the value using that getter:
while (self.x != 1) {
// keep observing for value change
}
It now works, because self.x is actually a call to a function and the compiler is polite enough to let the function actually do its job. However, I think this is a rather convoluted way to do something so simple. Is there any other way you would have coded it, another pattern that you will use, if you are faced with the task of "observing for change of value inside a block"? Thanks a lot!
If you use a variable and do not modify it in a loop, the compiler optimization can cause the actual access to the variable to be optimized out, because your statement can be evaluated beforehand at compile time.
In order to prevent this, you can use the "volatile" keyword, which prevents the compiler from applying this type of optimization.
It does work with getters and setters, because then you need to send a message to your instance, which serves as a synchronization point.
Try declaring _x as follows:
__block int _x;
Normally variables that are also used in blocks are copied. This will indicate to the compiler that if _x is modified in the block the changes should be visible outside it. It might fix your problem.
I'm running into a weird issue with XCode 4.5, the one supporting the new iOS6.
In most of my apps, I make a State class as a singleton accessible from everywhere for convenience, but with latest XCode, it seems like after I set any non-static pointer member to some object, right after the assignment the value is back to NULL.
Even weirder is I only see the issue if I start a new project from scratch, not if I load an older project created with an earlier version of XCode. I looked at compiler settings, and everything looks the same. The issue only appears if I test on the actual device (iPhone4 running iOS6). The simulator does not show this problem.
Here's the relevent code :
State.h
class State
{
public:
State();
~State();
static State& Get();
private:
static State * s_state;
State.mm
State* State::s_state = nil;
State& State::Get()
{
if(s_state==nil)
s_state = new State();
return *(s_state);
}
Example usage assuming State has a non-static member Object * m_object :
void SomeClass::DoSomething()
{
State::Get().SetObject( new Object() );
// this will return null with newly created XCode 4.5 projects
State::Get().GetObject();
** EDIT **
Regarding thread safety-ness, I'd like to know if the 2 cases below are considered "multi-threaded" scenarios.
I have one timer using display link for my opengl loop
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
And I have one timer responsible for updating the game logic that I init this way
timer = [NSTimer scheduledTimerWithTimeInterval:1.f/60.f target:self selector:#selector(timerUpdate) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:m_timer forMode:NSRunLoopCommonModes];
So if I call State::Get() from both these loops, is this considered a threaded scenario?
Thank you for your help.
- Marc
Your code looks okay (although it is not threadsafe). You don't post accessors, so I'll assume they are the standard type that actually get and set things.
Which means I can only guess but it's worth checking if the source of the problem is some corrupted memory that occurred earlier due to something like double delete.
Enable guard malloc and try again. You can also try valgrind.
About your edit, you should be okay as long as you are calling the addToLoop code from the main thread (you probably are calling it in some viewDidLoad or init code which is on the main thread), since both timer callbacks (timer and display link will be processed on the main loop).
Ok I found out what my issue was and thought I'd share with you all. Although it doesn't have anything to do with single/static classes, this kind of issue can be hard to debug.
In my State class, I had a member available only to a specific config :
#ifdef SOME_CONFIG
int m_someValue;
#endif
The problem in this case was that at compile time, SOME_CONFIG was actually defined, but undefined elsewhere according to target conditionals etc, causing the variable to exist on the stack but never inited/used etc. Just having the variable in the header was causing the issue (even if I didn't make any call using it.)
Hope this can help someone out there.
Thanks.
In my program I use KVO manually to observe changes to values of object properties. I receive an EXC_BAD_ACCESS signal at the following line of code inside a custom setter:
[self willChangeValueForKey:#"mykey"];
The weird thing is that this happens when a factory method calls the custom setter and there should not be any observers around. I do not know how to debug this situation.
Update: The way to list all registered observers is observationInfo. It turned out that there was indeed an object listed that points to an invalid address. However, I have no idea at all how it got there.
Update 2: Apparently, the same object and method callback can be registered several times for a given object - resulting in identical entries in the observed object's observationInfo. When removing the registration only one of these entries is removed. This behavior is a little counter-intuitive (and it certainly is a bug in my program to add multiple entries at all), but this does not explain how spurious observers can mysteriously show up in freshly allocated objects (unless there is some caching/reuse going on that I am unaware of).
Modified question: How can I figure out WHERE and WHEN an object got registered as an observer?
Update 3: Specific sample code.
ContentObj is a class that has a dictionary as a property named mykey. It overrides:
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {
BOOL automatic = NO;
if ([theKey isEqualToString:#"mykey"]) {
automatic = NO;
} else {
automatic=[super automaticallyNotifiesObserversForKey:theKey];
}
return automatic;
}
A couple of properties have getters and setters as follows:
- (CGFloat)value {
return [[[self mykey] objectForKey:#"value"] floatValue];
}
- (void)setValue:(CGFloat)aValue {
[self willChangeValueForKey:#"mykey"];
[[self mykey] setObject:[NSNumber numberWithFloat:aValue]
forKey:#"value"];
[self didChangeValueForKey:#"mykey"];
}
The container class has a property contents of class NSMutableArray which holds instances of class ContentObj. It has a couple of methods that manually handle registrations:
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {
BOOL automatic = NO;
if ([theKey isEqualToString:#"contents"]) {
automatic = NO;
} else {
automatic=[super automaticallyNotifiesObserversForKey:theKey];
}
return automatic;
}
- (void)observeContent:(ContentObj *)cObj {
[cObj addObserver:self
forKeyPath:#"mykey"
options:0
context:NULL];
}
- (void)removeObserveContent:(ContentObj *)cObj {
[cObj removeObserver:self
forKeyPath:#"mykey"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if (([keyPath isEqualToString:#"mykey"]) &&
([object isKindOfClass:[ContentObj class]])) {
[self willChangeValueForKey:#"contents"];
[self didChangeValueForKey:#"contents"];
}
}
There are several methods in the container class that modify contents. They look as follows:
- (void)addContent:(ContentObj *)cObj {
[self willChangeValueForKey:#"contents"];
[self observeDatum:cObj];
[[self contents] addObject:cObj];
[self didChangeValueForKey:#"contents"];
}
And a couple of others that provide similar functionality to the array. They all work by adding/removing themselves as observers. Obviously, anything that results in multiple registrations is a bug and could sit somewhere hidden in these methods.
My question targets strategies on how to debug this kind of situation. Alternatively, please feel free to provide an alternative strategy for implementing this kind of notification/observer pattern.
Update 4: I found the bug using a mixture of breakpoints, NSLogs, code reviews and sweating. I did not use the context in KVO, although this is definitely another useful suggestion. It was indeed a wrong double registration that - for reasons beyond my comprehension - resulted in the observed behavior.
The implementation including [self willChange...]; [self didChange...] works as described (on iOS 5), although it is far from beautiful. The issue is that as NSArray is not KVO-compliant there is no way to talk about changes to its contents. I had also thought about notifications as suggested by Mike Ash, but I decided to go with KVO as this seemed like a more Cocoa-ish mechanism to do the work. This was arguably not the best of decisions ...
Yes, calling -addObserver: twice will result in two registrations. A class Foo and some subclass of Foo, Bar, may both (legitimately) register for the same notification, but with different contexts (always include the context, always check the context in -observeValueForKeyPath and always call super in -observeValueForKeyPath).
This means that an instance of Bar will register twice, and this is correct.
However, you almost certainly don't want to register the same object/keypath/context more than once accidentally, and as #wbyoung says overriding -addObserver:forKeyPath:options:context: should help you make sure this doesn't happen. If nesessary keeping track of observers/keypath/context in an array and making sure they are unique.
Mike Ash has some interesting thoughts and code on his blog about using contexts. He is right about it being broken but in practise KVO is perfectly useable.
That is, when you use it to do something it is meant todo. It used to be that you absolutely could not do something like this..
[self willChangeValueForKey:#"contents"];
[self didChangeValueForKey:#"contents"];
because it's a lie. The value of 'contents' when you call -willChange.. must be a different value from when you call -didChange... The KVO mechanism will call -valueForKey:#"contents" in both -willChangeValueForKey and -didChangeValueForKey to verify the value has changed. This obviously won't work with an array as no matter how you modify the contents you still have the same object. Now i don't know if this is still the case (a web search turned up nothing) but note that -willChangeValueForKey, -didChangeValueForKey are not the correct way to handle manual kvo of a collection. For that Apple provides alternative methods:-
– willChange:valuesAtIndexes:forKey:
– didChange:valuesAtIndexes:forKey:
– willChangeValueForKey:withSetMutation:usingObjects:
– didChangeValueForKey:withSetMutation:usingObjects:
It may not still be true that the value must change, but if it is, your scheme is not going to work.
What i would do is have one notification for modifications to your collection. And a different notification for modification of items in that collection. i.e. at the moment you are trying to trigger notifications for #"contents" when instead you could have #"contents" and #"propertiesOfContents". You would need to observe two keypaths but you can use automatic kvo instead of manually triggering the notifications. (Using automatic kvo will ensure that the correct versions of -willChange.. -didChange.. are called)
For automatic kvo of an array take a look at (no NSArrayController needed) :-
Key-Value-Observing a to-many relationship in Cocoa
Then each time an item is added to the collection, observe the properties you need (as you are doing now) and when they change flip a value for self.propertiesOfContents. (ok as i read that back it doesn't necessarily sound less hacky than your solution but i still believe it may behave better).
In response to your modified question, try overriding addObserver:forKeyPath:options:context: in your custom class and setting a breakpoint on it. Alternatively, you can just set a symbolic breakpoint on -[NSObject addObserver:forKeyPath:options:context:], but that will probably get hit a lot.
I am using FMDB to deal with my database which works fine. The app uses a background thread which is doing some work and needs to access the database. At the same time the main thread needs to run some queries on the same database. FMDB itself has a little locking system, however, I added another to my classes.
Every query is only performed if my class indicates that the database is not in use. After performing the actions the database gets unlocked. This works as expected as long as the load is not too high. When I access a lot of data with the thread running on the main thread an EXC_BAD_ACCESS error occurs.
Here is the looking:
- (BOOL)isDatabaseLocked {
return isDatabaseLocked;
}
- (Pile *)lockDatabase {
isDatabaseLocked = YES;
return self;
}
- (FMDatabase *)lockedDatabase {
#synchronized(self) {
while ([self isDatabaseLocked]) {
usleep(20);
//NSLog(#"Waiting until database gets unlocked...");
}
isDatabaseLocked = YES;
return self.database;
}
}
- (Pile *)unlockDatabase {
isDatabaseLocked = NO;
return self;
}
The debugger says that the error occurs at [FMResultSet next] at the line
rc = sqlite3_step(statement.statement);
I double checked all retain counts and all objects do exist at this time. Again, it only occurs when the main thread starts a lot of queries while the background thread is running (which itself always produce heavy load). The error is always produced by the main thread, never by the background thread.
My last idea would be that both threads run lockedDatabase at the same time so they could get a database object. That's why I added the mutex locking via "#synchronized(self)". However, this did not help.
Does anybody have a clue?
SQLite provides a much simpler serialization. By just setting the sqlite_config() option SQLITE_CONFIG_SERIALIZED you will probably avoid most of these kinds of headaches. I discovered this the hard way after fighting with threading issues for a long while.
Here's how you use it, you can put it in the init method of FMDatabase...
if (sqlite3_config(SQLITE_CONFIG_SERIALIZED) == SQLITE_ERROR) {
NSLog(#"couldn't set serialized mode");
}
See the SQLite docs on threadsafety and serialized mode for more info.
You should add the synchronized wrapper around your functions unlockDatabase and lockDatabase, as well as isDatabaseLocked - it's not always guaranteed that a store or retrieval of a variable is atomic. Of course, if you do you'll want to move your sleep outside of the synchronized block, otherwise you'll deadlock. This is essentially a spin lock - it's not the most efficient method.
- (FMDatabase *)lockedDatabase {
do
{
#synchronized(self) {
if (![self isDatabaseLocked]) {
isDatabaseLocked = YES;
return self.database;
}
}
usleep(20);
}while(true); // continue until we get a lock
}
Do you make sure that you don't use the FMDatabase object after having called unlockDatabase? You might want to consider a handle pattern - create an object that wraps the FMDatabase object, and as long as it exists, holds a lock on the database. In init you claim the lock, and in dealloc, you can release that lock. Then your client code doesn't need to worry about calling the various locking/unlocking functions, and you won't accidentally screw up. Try using NSMutex instead of the #synchronized blocks, see http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html#//apple_ref/doc/uid/10000057i-CH8-SW16
You might also try FMDatabaseQueue - I created it specifically for situations like this. I haven't tried it, but I'm fairly sure it'll work for iOS 4.
I was having this problem and was able to eliminate the problem merely by turning on caching of prepared statements.
FMDatabase *myDatabase = [FMDatabase databaseWithPath: pathToDatabase];
myDatabase.shouldCacheStatements = YES;