在Xcode 6中使用XCTest进行订购单元测试

Boi*_*ime 30 xcode objective-c ios xctest xcode6

我想知道是否有任何方法告诉Xcode以指定的顺序运行单元测试.我的意思是不是在同一个XCTestCase类文件中,而是在所有类文件之间.

在此输入图像描述

例如,我想在运行SitchozrSDKMessageTest之前运行SitchozrSDKSessionTest.

我在堆栈或Apple文档上查看了几个线程,但我没有找到有用的东西.

谢谢你的帮助.

Jak*_*lik 28

它按字母顺序排序(类和方法).因此,当您需要最后运行的某些测试时,只需更改Class或Method的名称(对于(讨厌的)示例,通过前缀'z_').

所以...你有类名:

MyAppTest1
  -testMethodA
  -testMethodB
MyAppTest2
  -testMethodC
  -testMethodD
Run Code Online (Sandbox Code Playgroud)

他们按此顺序运行.如果你需要运行MyAppTest1作为第二个,只需重命名,以便它的名称按字母顺序排在MyAppTest2(z_MyAppTest1)之后,它将运行(方法相同):

MyAppTest2
  -a_testMethodD
  -testMethodC
z_MyAppTest1
  -testMethodA
  -testMethodB
Run Code Online (Sandbox Code Playgroud)

另请以命名为例:)

  • 应该注意的是,Xcode 8中不再存在这种情况 (21认同)

And*_*sen 15

确实,当前(从Xcode 7开始),XCTestCase方法按字母顺序运行,因此您可以通过巧妙地命名它们来强制命令.但是,这是一个实现细节,似乎可能会改变.

(希望)不那么脆弱的方法是按照您希望测试运行的顺序覆盖+[XCTestCase testInvocations]并返回自己的NSInvocation对象.

就像是:

+ (NSArray *)testInvocations
{
    NSArray *selectorStrings = @[@"testFirstThing",
                                 @"testSecondThing",
                                 @"testAnotherThing",
                                 @"testLastThing"];

    NSMutableArray *result = [NSMutableArray array];
    for (NSString *selectorString in selectorStrings) {
        SEL selector = NSSelectorFromString(selectorString);
        NSMethodSignature *methodSignature = [self instanceMethodSignatureForSelector:selector];
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
        invocation.selector = selector;
        [result addObject:invocation];
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

当然,这里的缺点是你必须手动添加每个测试方法,而不是自动拾取它们.有几种方法可以改善这种情况.如果您只需要订购一些测试方法,而不是所有测试方法,在您的覆盖中+testInvocations,您可以调用super,过滤掉您手动订购的那些方法,然后将其余部分添加到结束时你返回的数组.如果您需要订购所有测试方法,您仍然可以获得调用super的结果,并验证手动创建的有序结果是否涵盖了所有自动拾取的方法.如果没有,您可以断言,如果您忘记添加任何方法,则会导致失败.

我不讨论编写必须以特定顺序运行的测试是否"正确"的讨论.我认为很少有这种情况有意义,但其他人可能不同意.


小智 7

按函数名称字母顺序排序,无论你如何在代码中订购它.例如:

-(void)testCFun(){};
-(void)testB2Fun(){};
-(void)testB1Fun(){};
Run Code Online (Sandbox Code Playgroud)

实际的执行顺序是:

  1. testB1Fun调用
  2. testB2Fun叫
  3. testCFun调用

  • 我不想在特定的测试类文件中订购测试,但是类文件本身. (3认同)

bas*_*svk 6

除了安德鲁 - 马德森的回答:
我创建了一个"智能" testInvocations类方法,用于搜索以"test"开头的选择器,并按字母顺序对它们进行排序.
因此,您不必NSArray单独维护选择器名称.

#import <objc/runtime.h>

+ (NSArray <NSInvocation *> *)testInvocations
{
    // Get the selectors of this class
    unsigned int mc = 0;
    Method *mlist = class_copyMethodList(self.class, &mc);
    NSMutableArray *selectorNames = [NSMutableArray array];
    for (int i = 0; i < mc; i++) {
        NSString *name = [NSString stringWithFormat:@"%s", sel_getName(method_getName(mlist[i]))];
        if (name.length > 4
            && [[name substringToIndex:4] isEqualToString:@"test"]) {
            [selectorNames addObject:name];
        }
    }

    // Sort them alphabetically
    [selectorNames sortUsingComparator:^NSComparisonResult(NSString * _Nonnull sel1, NSString * _Nonnull sel2) {
        return [sel1 compare:sel2];
    }];

    // Build the NSArray with NSInvocations
    NSMutableArray *result = [NSMutableArray array];
    for (NSString *selectorString in selectorNames) {
        SEL selector = NSSelectorFromString(selectorString);
        NSMethodSignature *methodSignature = [self instanceMethodSignatureForSelector:selector];
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
        invocation.selector = selector;
        [result addObject:invocation];
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

脚注:认为单元测试依赖于彼此是不好的做法