Fre*_*ame 18 unit-testing objective-c objective-c-runtime ios xcode7
我发现Xcode 7(版本7.0(7A220))改变了+load在单元测试期间调用类和类别的方法的顺序.
如果属于测试目标的类别实现了一个+load方法,那么现在可以在最后调用它,此时类的实例可能已经被创建和使用.
我有一个AppDelegate实现+load方法.该AppDelegate.m文件还包含AppDelegate (MainModule)类别.此外,还有一个单元测试文件LoadMethodTestTests.m,其中包含另一个类别 - AppDelegate (UnitTest).
这两个类别也实现了+load方法.第一类属于主要目标,第二类属于测试目标.
我做了一个小测试项目来证明这个问题.它是一个空的默认Xcode一个视图项目,只更改了两个文件.
AppDelegate.m:
#import "AppDelegate.h"
@implementation AppDelegate
+(void)load {
NSLog(@"Class load");
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(@"didFinishLaunchingWithOptions");
return YES;
}
@end
@interface AppDelegate (MainModule)
@end
@implementation AppDelegate (MainModule)
+(void)load {
NSLog(@"Main Module +load");
}
@end
Run Code Online (Sandbox Code Playgroud)
和一个单元测试文件(LoadMethodTestTests.m):
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import "AppDelegate.h"
@interface LoadMethodTestTests : XCTestCase
@end
@interface AppDelegate (UnitTest)
@end
@implementation AppDelegate (UnitTest)
+(void)load {
NSLog(@"Unit Test +load");
}
@end
@implementation LoadMethodTestTests
-(void)testEmptyTest {
XCTAssert(YES);
}
@end
Run Code Online (Sandbox Code Playgroud)
我在Xcode 6/7上执行了这个项目的单元测试(代码和github链接在下面)并获得了以下+load调用顺序:
Xcode 6 (iOS 8.4 simulator):
Unit Test +load
Class load
Main Module +load
didFinishLaunchingWithOptions
Xcode 7 (iOS 9 simulator):
Class load
Main Module +load
didFinishLaunchingWithOptions
Unit Test +load
Xcode 7 (iOS 8.4 simulator):
Class load
Main Module +load
didFinishLaunchingWithOptions
Unit Test +load
Run Code Online (Sandbox Code Playgroud)
Xcode 7 在已经创建之后最终运行测试目标类别+load方法(Unit Test +load)AppDelegate.
这是一个正确的行为还是应该发送给Apple的错误?
可能是没有指定,所以编译器/运行时可以自由重新排列调用?我看了一下这个SO问题以及NSObject文档中的+ load描述,但我不太明白+load当类别属于另一个目标时该方法应该如何工作.
或者AppDelegate出于某种原因可能是某种特殊情况?
applicationDidFinishLaunchingWithOptions在发生混合之前执行.我相信还有其他方法可以做到这一点,但它对我来说在Xcode 7中的工作方式似乎是违反直觉的.我认为当一个类被加载到内存中时,+load这个类+load的所有类别的方法都被认为是在我们可以使用这个类之前调用(比如创建一个实例和调用didFinishLaunching...).Ric*_*III 21
这是因为xctest可执行文件(实际运行单元的那个,在$XCODE_DIR/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Agents/xctest加载它的bundle时).
在X-X之前,它在运行任何测试之前加载了所有引用的测试包.这可以看出(对于那些关心的人),通过反汇编Xcode 6.4的二进制文件,可以看到符号的相关部分-[XCTestTool runTestFromBundle:].
在Xcode 7版本中xctest,您可以看到它延迟了测试包的加载,直到XCTestSuite在实际XCTest框架中运行实际测试,这可以在符号中看到,该符号__XCTestMain仅在测试的主机应用程序设置之后被调用 -起来.
由于内部调用的顺序发生了变化,因此+load调用测试方法的方式也不同.对objective-c-runtime的内部结构没有任何更改.
如果要在应用程序中修复此问题,可以执行一些操作.首先,您可以使用手动加载捆绑包+[NSBundle bundleWithPath:],然后调用-load它.
您还可以将测试目标链接回测试主机应用程序(我希望您使用的是单独的测试主机而不是主应用程序!),这将使其在xctest加载主机应用程序时自动加载.
我不认为它是一个错误,它只是XCTest的一个实现细节.
资料来源:过去3天只需花费xctest一个完全不相关的原因进行拆解.
| 归档时间: |
|
| 查看次数: |
1891 次 |
| 最近记录: |