ios技巧 -- 单元测试

单元测试:是检查是否每个代码单元(例如类或函数)是否能产⽣预期
的结果。
单元测试是独⽴运⾏的,不依赖于其他模块或组件。

FIRST

  1. Fast:测试模块应该是快速⾼效的;
  2. Independent/Isolated:测试模块应该是独⽴相互不影响的;
  3. Repeatable :测试实例应该是可以重复使⽤的,测试结果应该是相同的;
  4. Self-validating:测试应完全⾃动化。输出结果要么是“成功”,要么是“失败”;
  5. Timely:理想情况下,应该在编写要测试的⽣产代码之前编写测试(测试驱动开发)。

单元测试需要启动APP。所以每次都会进行加载,产生耗时操作,所以这个时候就需要在测试的启动自己的FakeAppDelegate
这个时候我们可以从main函数中进行调试

int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    @autoreleasepool {
        // Setup code that might create autoreleased objects goes here.

        appDelegateClassName = NSStringFromClass([AppDelegate class]);
    }
    return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}

原理只要将appDelegateClassName换成我们自己的测试FakeAppDelegate就可以了,但是会将自己整成的程序污染,这个时候就需要NSStringFromClass,NSStringFromClass只有被编译的类才会查找到,而UnitTest类只有测试时才会参与编译,所以我们可以改成

int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    @autoreleasepool {
        // 方法 字符串->class
        id cls = NSClassFromString(@"XCTest");
        appDelegateClassName = cls ?  @"FakeAppDelgate" : NSStringFromClass([AppDelegate class]);
    }
    // 进行单元测试的时候 FakeAppDelgate
    return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}

swift中也是同理
新建main.swift


let cls = NSClassFromString("XCTest") != nil
let appDelegateClassName = cls ? NSStringFromClass(LGFakeAppDelegate.self) : NSStringFromClass(AppDelegate.self)

UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, appDelegateClassName)

编译完成之后我们我们打开app包所在位置,除了我们应用的app包还有个测试包

测试包.png

里面有几个动态库,我们的单元测试是不是有个方法进入,我们引入这个库,位置是 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Frameworks
我们通过xcconfig来引入

// 1. header
HEADER_SEARCH_PATHS = $(inherited) "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Frameworks/XCTest.framework/Headers"
//2.链接动态库

// 传统方式
OTHER_LDFLAGS = $(inherited) -F"/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Frameworks" -framework "XCTest"

LD_RUNPATH_SEARCH_PATHS = $(inherited) "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Frameworks"

这个时候我们只要导入#import 就可以在项目中直接使用单元测试,我们把test.m中的内容拷贝进入。

    XCTestSuite *suite = [XCTestSuite defaultTestSuite];
    // 初始化 testCase
    LoginAppUITests *testCase = [LoginAppUITests new];
    // testCase -》 suite
    [suite addTest:testCase];
    for (XCTest *test in suite.tests) {
        [test runTest];
    }

如果直接创建就相当于执行一个单元测试,测试完就会崩溃,主要是[XCTestSuite defaultTestSuite]只能执行一次。

//起个别名
    XCTestSuite *suite = [XCTestSuite testSuiteWithName:@"MyTest"];
//指定某个方法
    [suite addTest:[LoginAppUITests testCaseWithSelector:@selector(testExample)]];
    
    for (XCTest *test in suite.tests) {
        [test runTest];
    }
}

OC&swift测试

swiftTest调用OC方法

新建一个测试文件swiftTest,会自动创建UnitTest工程的桥接文件,再在主工程创建swift类生成主工程的桥接文件,在主工程桥接文件中导入创建的类,在swiftTest导入主工程模块,就可以直接使用了。

导入主模块.png

如果要测试swift代码就需要@testable import "testApp",这样就可以支持测试open,public, internal权限的代码

OC调用swift方法

直接#import "testApp-Swift.h"会提示无法找到,这时候需要在TARGET找到单元测试的target,在buildsetting中的Header Search Path中将路径添加进去$CONFIGURATION_TEMP_DIR/testApp.build/DerivedSources,注意修改自己的项目名称

你可能感兴趣的:(ios技巧 -- 单元测试)