Reputation: 225
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.
Upvotes: 1
Views: 792
Reputation: 9212
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.
Upvotes: 2
Reputation: 20980
Right, don't use NSAssert. Instead:
STFail
on anything that isn't successfully set up.-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.
Upvotes: 1