I have known about unit testing for a while now, but I am just now finally understanding how to implement it. I think that my initial implementation is a little rough so I could use some feedback.
I have implemented these tests in order to verify that a new feature of my strategy game is working properly. Previously, I would have output these values to the screen somewhere and simply watched to make sure that the expected behavior was happening. With these tests, I have concrete proof that the feature is working. This is much better!
However there are some problems. I needed to implement a Testing category for the class that I am testing because some of the methods I needed to run the tests are private. By creating this category at the top of the testing class, I can use private methods from the class without having to permanently expose them. This works, but I have heard that I should only be unit testing public methods, so I am wondering if what I have done is acceptable. I should note that I also had to add a couple getter methods to the class to get some information that was not public.
DTDwarfTests.m
#import <XCTest/XCTest.h>
#import "DTDwarf.h"
#import "DTJobUnit.h"
@interface DTDwarf (Testing)
-(void) setMoodForTesting:(int)moodAmount;
-(void) startJobCountdown:(JobType)jobType;
-(BOOL) doJobCountdown;
-(void) calculateMoodState;
-(void) calculateMoodAmountForJob;
-(JobType) getFavoriteJob;
-(JobType) getHatedJob;
@end
@interface DTDwarfTests : XCTestCase
@end
@implementation DTDwarfTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
-(void) testMoodInitialization {
DTDwarf *dwarf = [[DTDwarf alloc]initWithWorldSize:CGSizeZero];
XCTAssert(dwarf.moodAmount > 0);
}
-(void) testFavoriteAndHatedJobsValues {
DTDwarf *dwarf = [[DTDwarf alloc]initWithWorldSize:CGSizeZero];
XCTAssert([dwarf getFavoriteJob] != JobTypeNumJobTypes);
XCTAssert([dwarf getHatedJob] != JobTypeNumJobTypes);
}
-(void) testFavoriteJobMoodInfluence {
DTDwarf *dwarf = [[DTDwarf alloc]initWithWorldSize:CGSizeZero];
[dwarf setMoodForTesting:0];
dwarf.dwarfJobUnit = [[DTJobUnit alloc]initWithJobType:[dwarf getFavoriteJob]];
[dwarf calculateMoodAmountForJob];
XCTAssert(dwarf.moodAmount > 0);
}
-(void) testHatedJobMoodInfluence {
DTDwarf *dwarf = [[DTDwarf alloc]initWithWorldSize:CGSizeZero];
[dwarf setMoodForTesting:1000];
dwarf.dwarfJobUnit = [[DTJobUnit alloc]initWithJobType:[dwarf getHatedJob]];
[dwarf calculateMoodAmountForJob];
XCTAssert(dwarf.moodAmount < 1000);
}
-(void) testBadMoodIncreasesCountdown {
DTDwarf *happyDwarf = [[DTDwarf alloc]initWithWorldSize:CGSizeZero];
[happyDwarf setMoodForTesting:1000];
[happyDwarf calculateMoodState];
[happyDwarf startJobCountdown:JobTypeMining];
int happyDwarfCountdown = 0;
while (![happyDwarf doJobCountdown]) {
happyDwarfCountdown++;
}
DTDwarf *sadDwarf = [[DTDwarf alloc]initWithWorldSize:CGSizeZero];
[sadDwarf setMoodForTesting:0];
[sadDwarf calculateMoodState];
[sadDwarf startJobCountdown:JobTypeMining];
int sadDwarfCountdown = 0;
while (![sadDwarf doJobCountdown]) {
sadDwarfCountdown++;
}
XCTAssert(happyDwarfCountdown < sadDwarfCountdown);
}
@end