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
Our progress was too slow like a snail's pace, but, today, we'll go far from yesterday. 
We already made compilable source code, but it does not work as our wish. 
Constructor should store specified method name to be tested, and method which is selected, should call method in class. 
So, i'll change one item to TODO list as follows.

TODO List
  • Call test method --> 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

and, here is its source code

WasRun.h

@interface WasRun : NSObject {

bool wasRun;

NSString* name; // <-- newly added for store method name to be called. 

}


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

- (void) testMethod;

- (bool) wasRun;

@end




WasRun.m

#import "WasRun.h"


@implementation WasRun


- (id) initWithName: (NSString*) methodName 

{

[super init];

wasRun = NO;

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

return self;

}


- (void) testMethod

{

SEL exeMethod = NSSelectorFromString(name);

[self performSelector: exeMethod];

}


- (bool) wasRun

{

return wasRun;

}

@end



Okay, it looks finished. Let's check we can complete this step.... Build and RUN!!! gogogo!!
...
What the hell -_-;; Critical runtime error is happen. maybe, there is some exceptional case...


Stack frame is loading.... it looks there is stack overflow... (actually, i'm very beginner at XCode...)


Debugger displays that what is problem. in my main function, i called test function which is named "testMethod". 
But, in WasRun class, "testMethod" is the name that test function's own name, and it called itself recursively!!!

So, i changed method name "testMethod" to "Run".  (Actually, in my text book, it is already changed -_-)

Rebuild it and run... Okay!! it works well ;-) 







Posted by yunseong
TAG TDD

There were some errors on our code, because 'WasRun' class is missed. Here is 'WasRun' class implementation. 
As mentioned in TDD, this class is only for compile successfully. 


WasRun.h

#import <Cocoa/Cocoa.h>


@interface WasRun : NSObject {

bool wasRun;

}


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

- (void) testMethod;

- (bool) wasRun;

@end


WasRun.m


#import "WasRun.h"


@implementation WasRun


- (id) initWithName: (NSString*) name 

{

[super init];

wasRun = NO;

return self;

}


- (void) testMethod

{

}


- (bool) wasRun

{

return wasRun;

}

@end


After add above class, compile is successful!!, but output is...


what is this -_-;;  (Actually, there is no wonder for this result... I'm satisfied with successful compilation -_-)



Posted by yunseong
TAG TDD
TODO List
  • Call test method
  • 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


First, we have to write test code in the TDD premise. I wrote these codes on main function in TDD_Practice.m file

WasRun* test = [[WasRun alloc] initWithName: @"testMethod"];

NSLog(@"%@", [test wasRun]);

[test testMethod];

NSLog(@"%@", [test wasRun]);


of course, there is no definition about 'WasRun', this routine is failed. We need to make WasRun class... at tommorrow -_-;;
Posted by yunseong
TAG TDD
이전버튼 1 이전버튼