为什么在单元测试中使用 UITableViewCell 会导致 Trace/BPT 陷阱?
我在下面创建的最小项目中有以下最小测试用例 GHUnit 自述文件:
#import <GHUnitIOS/GHUnitIOS.h>
#import <UIKit/UIKit.h>
@interface MyTest : GHTestCase { }
@end
@implementation MyTest
- (BOOL)shouldRunOnMainThread {
return YES;
}
- (void)testFoo {
UITableViewCell *cell =
[[UITableViewCell alloc] initWithStyle:UITableViewStylePlain
reuseIdentifier:@"foo"];
NSLog(@"cell: %@", cell);
NSLog(@"cell.textLabel: %@", cell.textLabel);
}
@end
当我在 Xcode 的模拟器中使用“构建”和“运行”时,它运行良好。然而,当我 在终端中运行以下命令:
GHUNIT_CLI=1 xcodebuild -target Tests -configuration Debug -sdk iphonesimulator4.0 build
我得到以下输出:
Running: /Users/<user>/Desktop/tmp/TestApp/build/Debug-iphonesimulator/Tests.app/Tests -RegisterForSystemEvents
Tests(39346) malloc: protecting edges
Tests(39346) malloc: recording malloc stacks to disk using standard recorder
Tests(39346) malloc: enabling scribbling to detect mods to free blocks
Tests(39346) malloc: process 39249 no longer exists, stack logs deleted from /tmp/stack-logs.39249.Tests.ac1JfL.index
Tests(39346) malloc: stack logs being written into /tmp/stack-logs.39346.Tests.t8LG4p.index
Test Suite 'Tests' started.
MyTest/testFoo 2010-09-06 23:24:25.006 Tests[39346:903] cell: <UITableViewCell: 0x5a6d190; frame = (0 0; 320 44); layer = <CALayer: 0x5a6d390>>
RunTests.sh: line 28: 39346 Trace/BPT trap $RUN_CMD
Command /bin/sh failed with exit code 133
Command /bin/sh failed with exit code 133
** BUILD FAILED **
OCUnit 也会发生这种“Trace/BPT Trap”问题,我希望 GHUnit 可以解决这个问题,但不能在命令行上解决。任何人都知道什么 是关于?这似乎与从你不熟悉的上下文中使用 UIKit 有关 应该是这样,但我不明白限制到底是什么。
I have the following minimal test case in a minimal project created following
the GHUnit README:
#import <GHUnitIOS/GHUnitIOS.h>
#import <UIKit/UIKit.h>
@interface MyTest : GHTestCase { }
@end
@implementation MyTest
- (BOOL)shouldRunOnMainThread {
return YES;
}
- (void)testFoo {
UITableViewCell *cell =
[[UITableViewCell alloc] initWithStyle:UITableViewStylePlain
reuseIdentifier:@"foo"];
NSLog(@"cell: %@", cell);
NSLog(@"cell.textLabel: %@", cell.textLabel);
}
@end
It runs fine when I use Build and Run in the simulator in Xcode. However, when I
run the following command in the terminal:
GHUNIT_CLI=1 xcodebuild -target Tests -configuration Debug -sdk iphonesimulator4.0 build
I get this output:
Running: /Users/<user>/Desktop/tmp/TestApp/build/Debug-iphonesimulator/Tests.app/Tests -RegisterForSystemEvents
Tests(39346) malloc: protecting edges
Tests(39346) malloc: recording malloc stacks to disk using standard recorder
Tests(39346) malloc: enabling scribbling to detect mods to free blocks
Tests(39346) malloc: process 39249 no longer exists, stack logs deleted from /tmp/stack-logs.39249.Tests.ac1JfL.index
Tests(39346) malloc: stack logs being written into /tmp/stack-logs.39346.Tests.t8LG4p.index
Test Suite 'Tests' started.
MyTest/testFoo 2010-09-06 23:24:25.006 Tests[39346:903] cell: <UITableViewCell: 0x5a6d190; frame = (0 0; 320 44); layer = <CALayer: 0x5a6d390>>
RunTests.sh: line 28: 39346 Trace/BPT trap $RUN_CMD
Command /bin/sh failed with exit code 133
Command /bin/sh failed with exit code 133
** BUILD FAILED **
This "Trace/BPT Trap" thing happens with OCUnit too, and I was hoping GHUnit
would solve it, but it doesn't on the command line. Anybody have any idea what
it's about? It seems to have to do with using UIKit from a context you're not
supposed to, but I don't understand what exactly the restriction is.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
当从命令行运行时,在 GHUnit 中测试 UIViews 和 UIViewControllers 时,我遇到过类似的崩溃,因为没有可供绘制视图的界面。
只要您不调用导致它们将自身绘制到屏幕上的方法,您就应该能够测试其中一些类中的逻辑。只要视图未添加到主视图层次结构中,您就可以初始化它。避开 UIView 中的 drawRect 和 UIViewController 中的 loadView 对我来说是有帮助的。
但是,如果您的视图中有需要测试的逻辑,也许移动逻辑会更容易?
I've had similar crashes when testing UIViews and UIViewControllers in GHUnit, when running from the command line because there is no interface for the views to be drawn to.
You should be able to test the logic in some of these classes as long as you don't call methods that cause them to draw themselves to the screen. You can init a view as long as it's not added to the main view hierarchy. Steering clear of drawRect in UIView and loadView in UIViewController was a help for me.
However, if you've got the kind of logic in your views that needs testing, maybe it would be easier to move the logic?
有许多 UIKit 类在运行的 UIApplication 上下文之外根本无法工作。例如,实例化任何尝试使用 UIFont(例如 UILabel)的东西都会在正在运行的 UIApplication 之外发生混乱(即分段错误或类似情况)。 UIActivityIndicatorView 也会同样失败。
实际上没有办法在模拟器或设备之外一致地测试依赖于 UIKit 的代码。幸运的是,您可以运行为模拟器编译的代码,而无需实际运行模拟器进程。我相信 iOS 测试的 GTM 设置可以做到这一点;我知道 Cedar 是针对 iOS 规范执行此操作的。我对 GHUnit 不太熟悉,无法判断它是否可以做到这一点。
如果您想从命令行运行这样的规范,您需要适当地设置一些环境变量。您需要将 DYLD_ROOT_PATH 设置为要链接的 iOS SDK 的目录,将 IPHONE_SIMULATOR_ROOT 设置为同一 SDK 目录,将 CFFIXED_USER_HOME 设置为非空目录(我使用随机临时目录)。设置完成后,您可以通过直接调用并在命令行上添加 -RegisterForSystemEvents 来执行针对模拟器 SDK 构建的二进制文件。
例如,您可以查看 Cedar Rakefile (我最熟悉这是因为我写了它;GTM 或 GHUnit 中可能存在其他同样有效的示例)。查看 :uispecs 任务中文件的底部,了解它运行的命令行。
There are a number of UIKit classes that simply don't work outside the context of a running UIApplication. For instance, instantiating anything that attempts to use UIFont (UILabel, for instance) will explode messily (i.e. segmentation fault, or similar) outside a running UIApplication. UIActivityIndicatorView will fail similarly.
There really is no way to consistently test code that depends upon UIKit outside of the simulator or device. Fortunately, you can run code compiled for the simulator without actually running the simulator process. I believe the GTM setup for iOS tests does this; I know that Cedar does this for iOS specs. I'm not familiar enough with GHUnit to say whether it can do this.
If you want to run specs like this from the command line you need to set some environment variables appropriately. You need to set DYLD_ROOT_PATH to the directory for the iOS SDK you're linking against, IPHONE_SIMULATOR_ROOT to the same SDK directory, and CFFIXED_USER_HOME to something non-empty (I use a random temp directory). Once these are set you can execute the binary that you built against the simulator SDK by invoking it directly and adding -RegisterForSystemEvents on the command line.
For an example, you can check out the Cedar Rakefile (I'm most familiar with this because I wrote it; other equally valid examples may exist in GTM or GHUnit). Look at the bottom of the file in the :uispecs task for the command line that it runs.