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.
Related
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.
I need ideas on the following -
In the main thread at some point of execution say Point A(sequential logic), I need to remember the state of execution and delegate the execution of some other logic onto another thread, and let the main thread handle the UI events etc. When the delegated logic completes on the other thread then the flow of execution should continue from the point A and should recollect the entire execution context and proceed as if it never paused there.
Regards,
Sunil Phani Manne
It's hard to implement this exactly the way you're saying (for example do(things)... yield(other_thread); ...do(more_things);.
Here are a couple other options I can think of (you'd have to implement these yourself, using delegates or notifications for example; I'm just giving a basic outline of how it would work):
do(things)
[object doStuffOnOtherThreadWithCallback:^{ // block-based
do(more_things)...
}];
or...
do(things)
[object doStuffOnOtherThreadWithCallbackTarget:self // target/selector-based
selector:#selector(callbackSelector)];
}
- (void)callbackSelector {
do(more_things)...
}
One option you have is encapsulating the whole sequential logic that comes after Point A in your delegate and then execute it on the main thread when the secondary thread ends.
In other words, when you start the thread by calling, e.g.
[NSThread detachNewThreadSelector:sel toTarget:target withObject:delegate]
you can implement your target target so that it has a specific selector completion that is called at the end of sel on the main thread, like this (this is the your delegate class):
#implementation YOURDelegateClass {
.....
-(void)completion {
}
-(void)sel {
...
...
[self performSelectorOnMainThread:#selector(#"completion") withObject:self];
}
}
Of course you have many sub-options available here, like using a different call to start the background execution, etc.
The important point is that: you have to encapsulate in a selector all the logic that comes after Point A, and that you have to schedule the execution of this selector on the main thread, in order to get back to your context (although your context will have changed in the meantime because you will also have updated the UI).
EDIT:
Having to schedule the execution on the main thread defeats blocks from being suitable for this kind of callback. On the other side, block have the advantage that they in some limited sense give you access to the same lexical context in which the block was defined (which is roughly what you call context).
A workaround for this could be the following. Before detaching the new thread, store in a delegate the block you would like to execute at completion:
typedef void(^CustomBlock)(void);
#property (nonatomic, copy) CustomBlock customBlock;
....
int a = ...
delegate.customBlock = ^{
NSLog(#"hello %d.....", a);
}
[NSThread detachNewThreadSelector:sel...
....
-(void)completion {
[self customBlock];
}
Of course, you only get the context preservation that is guaranteed to you by block. But here you hit against a limit of the language.
If you need more context preservation, then the only possibility is encapsulating that context in your delegate class ivars.
One thing is for sure. There, most probably, isn't any direct feature in Cocoa that does that. Since you're saying that you can't duplicate the resources onto the new thread (for a very good reason), I am going to suggest that you make use of NSUndoManager. For every change you make in the thread, push an undo operation for that change onto the undo manager. At the end of the thread, execute all the undo operations in the undo manager object. This should, if done correctly, restore your state. Now, since the idea is untested, there could be a chance that not all actions can be undone. You will have to check that out first.
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.
I have a library project that uses ASIHTTPRequest to make URL requests and parse the responses. The library will be used by a separate iPhone app project.
If my iPhone controller code responds to a touch event, then calls into the library to make URL requests, how do I best perform the requests asynchronously?
In the library, if I use the delegate pattern for asynchronous requests as shown in the ASIHTTPRequest sample code, how do I return data from the library back to the calling code in the iPhone controller?
If I instead make synchronous URL requests with ASIHTTPRequest inside the library, what's the easiest way to put the calls to the library from the iPhone controller on a separate thread to avoid tying up the UI thread?
I'm no ASIHTTPRequest expert (NSURLRequest has always done me fine), but from a quick poke at the code, it looks like you'd use its delegate and didFinishSelector properties to give it someone to tell when the URL request is finished. So, for example:
- (void)startURLRequest
{
ASIHTTPRequest *myRequest;
/* code to set the request up with your target URL, etc here */
myRequest.delegate = self;
myRequest.didFinishSelector = #selector(HTTPRequestDidFinish:);
/* ... */
[myRequest startAsynchronous];
}
- (void)HTTPRequestDidFinish:(ASIHTTPRequest *)request
{
NSLog(#"Request %# did finish, got data: %#", request, request.data);
[myTargetForData didReceiveData:request.data fromURL:request.originalURL];
}
Apple explicitly recommend that you use the built-in runloop style mechanisms for asynchronous HTTP fetching, not separate threads. Using separate threads is likely to result in worse performance — at least in terms of battery life and/or device heat, even if it's still fast enough.
That said, as a learning point, by far the quickest way to switch something onto a separate thread and have it report back to the main thread (remember: UIKit objects may be messaged only from the main thread) is by changing this:
- (void)postResult:(NSString *)result
{
instanceOfUILabel.text = result;
}
- (void)doExpensiveOperationOn:(NSString *)source
{
/* lots of expensive processing here, and then... */
[self postResult:result];
}
- (IBAction)userWantsOperationDone:(id)sender
{
[self doExpensiveOperationOn:#"some value or another"];
}
Into this:
- (void)postResult:(NSString *)result
{
instanceOfUILabel.text = result;
}
- (void)doExpensiveOperationOn:(NSString *)source
{
/* we're on a thread without an autorelease pool now, probably we'll want one */
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
/* lots of expensive processing here, and then... */
/* in this simplified example, we assume that ownership of 'result' is here on this thread, possibly on the autorelease pool, so wait until postResult has definitely finished before doing anything that might release result */
[self performSelectorOnMainThread:#selector(postResult:) withObject:result waitUntilDone:YES];
[pool release];
}
- (IBAction)userWantsOperationDone:(id)sender
{
[self performSelectorOnBackgroundThread:#selector(doExpensiveOperationOn:) withObject:#"some value or another"];
}
There's about a million possible concurrency errors you can make by just going threaded without thinking about it though, and in that example an obvious problem is that whatever triggered the IBAction can [probably] trigger it several more times before doExpensiveOperationOn has finished. Multithreading is not something to be dashed into lightly.
For anyone's future reference, the easiest approach I found is to use the async request functionality built into ASIHTTPRequest, setting my library object as the delegate and setting the didFinishSelector: and didFailSelector: values to different methods inside my library for each request.
At the end of processing each response, I assign the parsed response (an NSString* or NSArray*) to a property of my library object instead of returning a value.
When my iOS view controller delegate is loaded, I add a change observer to each of the properties in the library using Key-Value Observing. When the response is parsed and assigned to the property in the library, the observeValueForKeyPath:ofObject:change:context: method is called in the code of my view controller delegate, and from there I can figure out which property was changed and therefore what UI needs to be updated.
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;