北武灵尊

记录一些事情,方便查阅。

XCTest测试属性变化

之前有一篇写XCTest异步测试,现在写一下对属性值变化的测试。比如设置某个属性的值,然后调用了某个方法后,值的变化是不是我们预期得到的。下面的代码是作者jtang写的,我修改了一句以适应ARC模式。

1、创建一个NSObject的扩展类(Category)

NSObject+Properties.h

#import <Foundation/Foundation.h>

@interface NSObject (Properties)

// 仅可用于单元测试 ivarName是成员变量名字,不是属性名字
// 对于对象直接返回,如果是原始数据类型.返回NSValue
// 示例:
// NSValue *value = [self getIvarFromString_ONLY_USE_IN_UNIT_TEST:@"_test"];
// int x;
// [value getValue:&x];
- (id)getIvarFromString_ONLY_USE_IN_UNIT_TEST:(NSString *)ivarName;

@end

NSObject+Properties.m

#import "NSObject+Properties.h"
#import <objc/runtime.h>

@implementation NSObject (Properties)

- (id)getIvarFromString_ONLY_USE_IN_UNIT_TEST:(NSString *)ivarName
{

    Ivar ivar = class_getInstanceVariable(self.class, [ivarName UTF8String]);
    //    Ivar ivar = object_getInstanceVariable(self, [ivarName UTF8String], NULL);

    if (ivar)
    {
        id ivarID = object_getIvar(self, ivar);
        const char *typeEncoding = ivar_getTypeEncoding(ivar);
        if (typeEncoding[0] == '@')
        {
            return ivarID;
        }
        else
        {
            return [NSValue valueWithBytes:&ivarID objCType:typeEncoding];
        }
    }

    return nil;
}

@end

2、用法举例

ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

- (void)test;

@end

ViewController.m

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, strong) NSString *userName;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    _userName = @"abc";
}

- (void)test {
    _userName = @"def";
}

@end

测试文件MyAppTests.m

#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import "ViewController.h"
#import "NSObject+Properties.h"

@interface MyAppTests : XCTestCase {
    // add instance variables to the CalcTests class

    ViewController  *viewController;
}

@end

@implementation MyAppTests

- (void)setUp {
    [super setUp];
    // Put setup code here. This method is called before the invocation of each test method in the class.
    viewController = [[ViewController alloc] init];
}

- (void)tearDown {
    // Put teardown code here. This method is called after the invocation of each test method in the class.
    [super tearDown];

}

- (void)testUserName {
    [viewController test];
    NSString *userName = (NSString *)[viewController getIvarFromString_ONLY_USE_IN_UNIT_TEST:@"_userName"];
    XCTAssertEqualObjects(userName, @"def", @"Sussess");
}

@end

3、测试UI变化

#import "TestSettingPickerCell_UI.h"
#import "SettingPickerCell.h"
#import "NSObject+Properties.h"

@implementation TestSettingPickerCell_UI
{
    SettingPickerCell *cell;
}


- (void)testsetCheckMarkYES
{
    UIImageView *checkImageView = [cell getIvarFromString_ONLY_USE_IN_UNIT_TEST:@"_mCheckImageView"];
    [cell setCheckMark:YES];
    STAssertEquals(checkImageView.image, [UIImage imageNamed:@"selected_green.png"],@"");
}

- (void)testsetCheckMarNO
{
    UIImageView *checkImageView = [cell getIvarFromString_ONLY_USE_IN_UNIT_TEST:@"_mCheckImageView"];
    [cell setCheckMark:NO];
    STAssertEquals(checkImageView.image, [UIImage imageNamed:@"CellUnchecked.png"],@"");
}

- (void)setUp
{
    [super setUp];
    cell = [[SettingPickerCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
}

- (void)tearDown
{
    [super tearDown];
}

@end