简体   繁体   English

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

[英]Ordering unit test using XCTest in Xcode 6

I would like to know if there is any way to tell Xcode to run unit tests in a specified order. 我想知道是否有任何方法告诉Xcode以指定的顺序运行单元测试。 I mean not in a same XCTestCase class file, but between all the class file. 我的意思是不是在同一个XCTestCase类文件中,而是在所有类文件之间。

在此输入图像描述

For example I want to run the SitchozrSDKSessionTest before running SitchozrSDKMessageTest. 例如,我想在运行SitchozrSDKMessageTest之前运行SitchozrSDKSessionTest。

I looked over few threads on stack or on Apple documentation and I haven't found something helpful. 我在堆栈或Apple文档上查看了几个线程,但我没有找到有用的东西。

Thanks for your help. 谢谢你的帮助。

It's all sorted alphabetically (classes and methods). 它按字母顺序排序(类和方法)。 So when You need some tests running last, just change the name of Class or Method (for (nasty) example by prefixing 'z_'). 因此,当您需要最后运行的某些测试时,只需更改Class或Method的名称(对于(讨厌的)示例,通过前缀'z_')。

So...You have Class names: 所以...你有类名:

MyAppTest1
  -testMethodA
  -testMethodB
MyAppTest2
  -testMethodC
  -testMethodD

and they run in this order. 他们按此顺序运行。 If you need to run MyAppTest1 as second, just rename so it's name is alphabetically after MyAppTest2 (z_MyAppTest1) and it will run (same for method): 如果你需要运行MyAppTest1作为第二个,只需重命名,以便它的名称按字母顺序排在MyAppTest2(z_MyAppTest1)之后,它将运行(方法相同):

MyAppTest2
  -a_testMethodD
  -testMethodC
z_MyAppTest1
  -testMethodA
  -testMethodB

Also please take the naming as example :) 另请以命名为例:)

It is true that currently (as of Xcode 7), XCTestCase methods are run in alphabetical order, so you can force an order for them by naming them cleverly. 确实,当前(从Xcode 7开始),XCTestCase方法按字母顺序运行,因此您可以通过巧妙地命名它们来强制命令。 However, this is an implementation detail and seems like it could change. 但是,这是一个实现细节,似乎可能会改变。

A (hopefully) less fragile way to do this is to override +[XCTestCase testInvocations] and return your own NSInvocation objects in the order you want the tests run. 一个(希望)不那么脆弱的方法是覆盖+[XCTestCase testInvocations]并按照您希望测试运行的顺序返回您自己的NSInvocation对象。

Something like: 就像是:

+ (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;
}

Of course, the downside here is that you have to manually add each test method to this instead of them being picked up automatically. 当然,这里的缺点是你必须手动添加每个测试方法,而不是自动拾取它们。 There are a few ways to improve this situation. 有几种方法可以改善这种情况。 If you only need to order some of your test methods, not all of them, in your override of +testInvocations , you could call through to super, filter out those methods that you've manually ordered, then tack the rest on to the end of the array you return. 如果你只需要在你的+testInvocations覆盖中订购一些测试方法,而不是所有测试方法,你可以调用super,过滤掉你手动订购的那些方法,然后将其余部分添加到最后你返回的数组。 If you need to order all the test methods, you could still get the result of calling through to super and verify that all of the automatically picked up methods are covered by your manually created, ordered result. 如果您需要订购所有测试方法,您仍然可以获得调用super的结果,并验证手动创建的有序结果是否涵盖了所有自动拾取的方法。 If not, you could assert, causing a failure if you've forgotten to add any methods. 如果没有,您可以断言,如果您忘记添加任何方法,则会导致失败。

I'm leaving aside the discussion of whether it's "correct" to write tests that must run in a certain order. 我不讨论编写必须以特定顺序运行的测试是否“正确”的讨论。 I think there are rare scenarios where that makes sense, but others may disagree. 我认为很少有这种情况有意义,但其他人可能不同意。

its ordered by function names letter orders, doesn't matter how you order it in your code. 按函数名称字母顺序排序,无论你如何在代码中订购它。 eg: 例如:

-(void)testCFun(){};
-(void)testB2Fun(){};
-(void)testB1Fun(){};

the actual execute order is : 实际的执行顺序是:

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

In addition to andrew-madsen 's answer: 除了安德鲁 - 马德森的回答:
I created a 'smart' testInvocations class method which searches for selectors starting with "test" and sorts them alphabetically. 我创建了一个'智能' testInvocations类方法,该方法搜索以“test”开头的选择器并按字母顺序对它们进行排序。
So you don't have to maintain an NSArray of selector names separately. 因此,您不必单独维护选择器名称的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;
}

Footnote: It's considered bad practice making your unit tests depend on eachother 脚注:认为单元测试依赖于彼此是不好的做法

For you exemple you can just rename the tests files on your project like this : 例如,您可以像这样重命名项目中的测试文件:

SitchozrSDKSessionTest -> t001_SitchozrSDKSessionTest
SitchozrSDKMessageTest -> t002_SitchozrSDKMessageTest

Xcode treat the files using alphabetic order. Xcode使用字母顺序处理文件。

Since Xcode 7, XCTestCase subclasses are alphabetically ordered. 从Xcode 7开始,XCTestCase子类按字母顺序排列。 If you want to ensure that the test methods themselves are also run in alphabetical order, you must override the testInvocations class method and return the invocations sorted by selector. 如果要确保测试方法本身也按字母顺序运行,则必须覆盖testInvocations类方法并返回按选择器排序的调用。

@interface MyTestCase : XCTestCase
@end

@implementation MyTestCase

+ (NSArray<NSInvocation *> *) testInvocations
{
    return [[super testInvocations] sortedArrayUsingComparator:^NSComparisonResult(NSInvocation *invocation1, NSInvocation *invocation2) {
        return [NSStringFromSelector(invocation1.selector) compare:NSStringFromSelector(invocation2.selector)];
    }];
}

- (void) test_01
{
}

- (void) test_02
{
}

@end

The OP did not mention whether CI is available or whether a command line answer would be sufficient. OP未提及CI是否可用或命令行答案是否足够。 In those cases, I have enjoyed using xctool [1]. 在那些情况下,我很喜欢使用xctool [1]。 It has syntax to run tests down to just a single test method: 它具有将测试运行到一个测试方法的语法:

path/to/xctool.sh \
  -workspace YourWorkspace.xcworkspace \
  -scheme YourScheme \
  test -only SomeTestTarget:SomeTestClass/testSomeMethod

I will do this to ensure we test the items we think are easiest first. 我会这样做,以确保我们测试我们认为最容易的项目。

1.[] facebook/xctool: A replacement for Apple's xcodebuild that makes it easier to build and test iOS or OSX apps. 1. [] facebook / xctool:Apple xcodebuild的替代品,可以更轻松地构建和测试iOS或OSX应用程序。 ; ; ; ; https://github.com/facebook/xctool https://github.com/facebook/xctool

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM