TODO List
  • Call test method dynamically. 
  • Call 'setUp' before calling test method
  • Call 'tearDown' after calling test method
  • Call 'teatDown' whether test is passed or  not
  • Execute multiple test cases
  • Print collected test case result

I think that i accomplished first step. but how about follows test code?

- (void) testRunning

{

WasRun* test = [[WasRun allocinitWithName@"NotExistedMethod"];

NSAssert([test wasRun] == NO@"wasRun Failed");

[test Run]; // Run with invalid method name.

NSAssert([test wasRun] == YES@"wasRun Failed");

}


In objective-C, if receiver receives unrecognized message by selector, it throws InvalidArgumentException. Hence, TestCase class has no try-catch statement, it crashed. Actually, the reason of this situation is from we cannot force that TestCase class has only one constructor. TestCase class can be instanced with "init" method, not only "initWithMethodName" method. What is more, there is no routine to validate given method name. So, before we go over next step, i'll make it more stable with add some TODO item. 

TODO List
  • Call test method dynamically. 
  • Handling exception caused by method name
  • Call 'setUp' before calling test method
  • Call 'tearDown' after calling test method
  • Call 'teatDown' whether test is passed or not
  • Execute multiple test cases
  • Print collected test case result
 

For our new requirement, i wrote 2 new TestCaseTest class method. 

- (void) testRunningWithInvalidMethodName

{

NSString* assertErrMsg = [[NSString allocinitWithString@"Assertion failed"];

WasRun* test = [[WasRun allocinitWithMethodName@"NotExistedMethod"];

NSAssert([test wasRun] == NO, assertErrMsg);

[test Run];

NSAssert([test wasRun] == NO, assertErrMsg);

NSLog(@"%s is finished\n", __FUNCTION__);

}


- (void) testRunningWithNoMethodName

{

NSString* assertErrMsg = [[NSString allocinitWithString@"Assertion failed"];

WasRun* test = [[WasRun allocinit];

NSAssert([test wasRun] == NO, assertErrMsg);

[test Run];

NSAssert([test wasRun] == NO, assertErrMsg);

NSLog(@"%s is finished\n", __FUNCTION__);

}


First is for when given not existed method name, and second is for with no name.

Above codes are compiled successfully. 

Okay, let's check first. 

For handle invalid test method name, we can use RTTI (Real-Time Type Information). Of course, Objective-C supports RTTI well. (In fact, Cocoa framework supports it). I modified "Run" method in TestCase class. 

- (void) Run

{

SEL exeMethod = NSSelectorFromString(name);


if ([self respondsToSelector: exeMethod] == YES)

{

[self performSelector: exeMethod];

}

else

{

NSLog(@"Given method named %@ cannot be resolved.", name);

}

}


Its result is



Okay. First issue (given invalid method name) is resolved. Let's check second issue, which is when receives no name. 


- (void) Run

{

    if (name != nil)

    {

        SEL exeMethod = NSSelectorFromString(name);

        if ([self respondsToSelector: exeMethod] == YES)

        {

       [self performSelector: exeMethod];

    }

else

{

    NSLog(@"[ERR]Given method named \"%@\" cannot be resolved.", name);

}

    }

    else

    {

NSLog(@"[ERR]TestCase class should be initiated with \"initWithMethodName\".\n");

    }

}



and test case execution code, here it is.

int main (int argc, const char * argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];


TestCaseTest* testCaseTest = [[TestCaseTest alloc] initWithMethodName: @"testRunning"];

[testCaseTest Run];

[testCaseTest release];

TestCaseTest* testCaseTest1 = [[TestCaseTest alloc] initWithMethodName: @"testRunningWithInvalidMethodName"];

[testCaseTest1 Run];

[testCaseTest1 release];

TestCaseTest* testCaseTest2 = [[TestCaseTest alloc] initWithMethodName: @"testRunningWithNoMethodName"];

[testCaseTest2 Run];

[testCaseTest2 release];

 

    [pool drain];

    return 0;

}



Finally, i completed second step!!


Actually, i read some chapters more far from rate of current progress. There is exception handling chapter after a few chapters, but i did it more earlier, because i don't think i have to follow that book. Of course, this exception handling is too simple. It can handle only caused by method name. If there is another runtime exception on executing test, this framework will be crashed. I know that i have to use careful try-catch statement, but i'll add it when i need it ;-). It is not now. 
Posted by yunseong
TAG TDD, xUnit
Actually, our "WasRun" class has multiple functionality.
first is Check test function is called or not, and second is calling test function in really. 

We need  to make it separate. WasRun is still check function is called or not, and new class will call test function. New class's name is "TestCase".


TestCase.h / TestCase.m


#import <Cocoa/Cocoa.h>



@interface TestCase : NSObject {

NSString* name;

}


- (id) initWithMethodName: (NSString*) methodName;

- (void) Run;


@end



#import "TestCase.h"



@implementation TestCase

- (id) initWithMethodName: (NSString*) methodName

{

[super init];

name = [[NSString alloc] initWithString: methodName];

return self;

}


- (void) Run

{

SEL exeMethod = NSSelectorFromString(name);

[self performSelector: exeMethod];

}


@end



WasRun.h / WasRun.m


#import <Cocoa/Cocoa.h>

#import "TestCase.h"


@interface WasRun : TestCase {

bool wasRun;

}


- (id) initWithName: (NSString*) methodName;

- (void) testMethod;

- (bool) wasRun;

@end



#import "WasRun.h"


@implementation WasRun


- (id) initWithName: (NSString*) methodName 

{

[super initWithMethodName: methodName];

wasRun = NO;

return self;

}


-(void) testMethod

{

wasRun = YES;

}


- (bool) wasRun

{

return wasRun;

}

@end



as you can show, WasRun class is only for check method is executed or not, and TestCase class is execution trigger. 

And of course, its execution result is...


Perfect!! ;-)


I have one more thing to tell. Actually, i don't be acquainted with Cocoa framework, so i cannot find how can i bind proper method by method's name. So i ask to 'Mac bu gi' club in portal site Naver, they reply to me in a hour!! Thanks ;)

 


Posted by yunseong
TAG TDD, xUnit
이전버튼 1 이전버튼