受到solution to this question的启发,我尝试使用与XCTest相同的方法。
我设置了'生成测试覆盖率文件= YES'和'仪器程序流程= YES'。
XCode仍然不会生成任何gcda文件。任何人都有任何想法如何解决这个问题?
代码:
#import <XCTest/XCTestLog.h>
@interface VATestObserver : XCTestLog
@end
static id mainSuite = nil;
@implementation VATestObserver
+ (void)initialize {
[[NSUserDefaults standardUserDefaults] setValue:@"VATestObserver"
forKey:XCTestObserverClassKey];
[super initialize];
}
- (void)testSuiteDidStart:(XCTestRun *)testRun {
[super testSuiteDidStart:testRun];
XCTestSuiteRun *suite = [[XCTestSuiteRun alloc] init];
[suite addTestRun:testRun];
if (mainSuite == nil) {
mainSuite = suite;
}
}
- (void)testSuiteDidStop:(XCTestRun *)testRun {
[super testSuiteDidStop:testRun];
XCTestSuiteRun *suite = [[XCTestSuiteRun alloc] init];
[suite addTestRun:testRun];
if (mainSuite == suite) {
UIApplication* application = [UIApplication sharedApplication];
[application.delegate applicationWillTerminate:application];
}
}
@end
在AppDelegate.m中我有:
extern void __gcov_flush(void);
- (void)applicationWillTerminate:(UIApplication *)application {
__gcov_flush();
}
编辑:我编辑了问题以反映当前状态(没有红色鲱鱼)。
编辑为了使其正常工作,我必须将测试中的所有文件添加到测试目标中,包括VATestObserver。
AppDelegate.m
#ifdef DEBUG
+ (void)initialize {
if([self class] == [AppDelegate class]) {
[[NSUserDefaults standardUserDefaults] setValue:@"VATestObserver"
forKey:@"XCTestObserverClass"];
}
}
#endif
VATestObserver.m
#import <XCTest/XCTestLog.h>
#import <XCTest/XCTestSuiteRun.h>
#import <XCTest/XCTest.h>
// Workaround for XCode 5 bug where __gcov_flush is not called properly when Test Coverage flags are set
@interface VATestObserver : XCTestLog
@end
#ifdef DEBUG
extern void __gcov_flush(void);
#endif
static NSUInteger sTestCounter = 0;
static id mainSuite = nil;
@implementation VATestObserver
+ (void)initialize {
[[NSUserDefaults standardUserDefaults] setValue:@"VATestObserver"
forKey:XCTestObserverClassKey];
[super initialize];
}
- (void)testSuiteDidStart:(XCTestRun *)testRun {
[super testSuiteDidStart:testRun];
XCTestSuiteRun *suite = [[XCTestSuiteRun alloc] init];
[suite addTestRun:testRun];
sTestCounter++;
if (mainSuite == nil) {
mainSuite = suite;
}
}
- (void)testSuiteDidStop:(XCTestRun *)testRun {
sTestCounter--;
[super testSuiteDidStop:testRun];
XCTestSuiteRun *suite = [[XCTestSuiteRun alloc] init];
[suite addTestRun:testRun];
if (sTestCounter == 0) {
__gcov_flush();
}
}
答案 0 :(得分:3)
因为你必须在testSuiteDidStop方法中创建一个新的XCTestSuiteRun实例,所以你不会在==检查中得到正确的结果。我们使用一个简单的计数器,并在它达到零时调用flush,而不是依赖于实例相等,这将在顶级XCTestSuite完成执行时调用。可能有更聪明的方法来做到这一点。
首先,我们必须在 测试和主应用目标中设置'生成测试覆盖率文件=是'和'仪器程序流量=是'。
#import <XCTest/XCTestLog.h>
#import <XCTest/XCTestSuiteRun.h>
#import <XCTest/XCTest.h>
// Workaround for XCode 5 bug where __gcov_flush is not called properly when Test Coverage flags are set
@interface GCovrTestObserver : XCTestLog
@end
#ifdef DEBUG
extern void __gcov_flush(void);
#endif
static NSUInteger sTestCounter = 0;
static id mainSuite = nil;
@implementation GCovrTestObserver
- (void)testSuiteDidStart:(XCTestRun *)testRun {
[super testSuiteDidStart:testRun];
XCTestSuiteRun *suite = [[XCTestSuiteRun alloc] init];
[suite addTestRun:testRun];
sTestCounter++;
if (mainSuite == nil) {
mainSuite = suite;
}
}
- (void)testSuiteDidStop:(XCTestRun *)testRun {
sTestCounter--;
[super testSuiteDidStop:testRun];
XCTestSuiteRun *suite = [[XCTestSuiteRun alloc] init];
[suite addTestRun:testRun];
if (sTestCounter == 0) {
__gcov_flush();
}
}
@end
还需要一个额外的步骤,因为当包含在测试目标中时,观察者没有进行+ initialize调用。
在AppDelegate中,添加以下内容:
#ifdef DEBUG
+(void) initialize {
if([self class] == [AppDelegate class]) {
[[NSUserDefaults standardUserDefaults] setValue:@"GCovrTestObserver"
forKey:@"XCTestObserverClass"];
}
}
#endif
答案 1 :(得分:1)
这是另一种避免编辑AppDelegate的解决方案
UIApplication + Instrumented.m(把它放在你的主要目标中):
@implementation UIApplication (Instrumented)
#ifdef DEBUG
+ (void)load
{
NSString* key = @"XCTestObserverClass";
NSString* observers = [[NSUserDefaults standardUserDefaults] stringForKey:key];
observers = [NSString stringWithFormat:@"%@,%@", observers, @"XCTCoverageFlusher"];
[[NSUserDefaults standardUserDefaults] setValue:observers forKey:key];
}
- (void)xtc_gcov_flush
{
extern void __gcov_flush(void);
__gcov_flush();
}
#endif
@end
XCTCoverageFlusher.m(把它放在你的测试目标中):
@interface XCTCoverageFlusher : XCTestObserver
@end
@implementation XCTCoverageFlusher
- (void) stopObserving
{
[super stopObserving];
UIApplication* application = [UIApplication sharedApplication];
SEL coverageFlusher = @selector(xtc_gcov_flush);
if ([application respondsToSelector:coverageFlusher])
{
objc_msgSend(application, coverageFlusher);
}
[application.delegate applicationWillTerminate:application];
}
@end
答案 2 :(得分:0)
- (void)applicationWillTerminate:(UIApplication*)application
,而不是在观察者类中定义。
我没有任何库问题。 “-lgov”不是必需的,您不必添加任何库。 LLVM编译器直接支持覆盖率。
答案 3 :(得分:0)
如果您正在使用Specta,那么这个过程会有所不同,因为它会自行调整。以下内容对我有用:
测试包
@interface MyReporter : SPTNestedReporter // keeps the default reporter style
@end
@implementation MyReporter
- (void) stopObserving
{
[super stopObserving];
UIApplication* application = [UIApplication sharedApplication];
[application.delegate applicationWillTerminate:application];
}
@end
<强>的AppDelegate:强>
- (void)applicationWillTerminate:(UIApplication *)application
{
#ifdef DEBUG
extern void __gcov_flush(void);
__gcov_flush();
#endif
}
然后,您需要通过在主方案的“运行”部分中将环境变量SPECTA_REPORTER_CLASS
设置为MyReporter
来启用自定义报告子类。
答案 4 :(得分:0)
GCOV Flush in - (void)applicationWillTerminate对我不起作用,我认为因为我的应用程序在后台运行。
我还设置了'生成测试覆盖率文件=是'和'仪器程序流程=是'但没有设置gcda文件。
然后我在TestClass的 - (void)tearDown中执行了“__gcov_flush()”,它为我的TestClass提供了gcda-Files;)
然后我在AppDelegate中创建了以下函数:
@interface AppDelegate : UIResponder <UIApplicationDelegate>
+(void)gcovFlush;
@end
@implementation AppDelegate
+(void)gcovFlush{
extern void __gcov_flush(void);
__gcov_flush();
NSLog(@"%s - GCOV FLUSH!", __PRETTY_FUNCTION__);
}
@end
我打电话给[AppDelegate gcovFlush] - (void)tearDown和voilá,还有我的gcda文件;)
我希望这有帮助,再见克里斯