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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26216828/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 05:47:40  来源:igfitidea点击:

Ordering unit test using XCTest in Xcode 6

iosobjective-cxcodexcode6xctest

提问by BoilingLime

I would like to know if there is any way to tell Xcode to run unit tests in a specified order. I mean not in a same XCTestCase class file, but between all the class file.

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

enter image description here

enter image description here

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.

谢谢你的帮助。

采纳答案by JakubKnejzlik

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_').

它都按字母顺序排序(类和方法)。因此,当您需要最后运行一些测试时,只需更改类或方法的名称(对于(讨厌的)示例,前缀为“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 :)

也请以命名为例:)

回答by Andrew Madsen

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. However, this is an implementation detail and seems like it could change.

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

A (hopefully) less fragile way to do this is to override +[XCTestCase testInvocations]and return your own NSInvocationobjects 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 someof 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. 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. If not, you could assert, causing a failure if you've forgotten to add any methods.

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

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.

我将讨论编写必须按特定顺序运行的测试是否“正确”。我认为在少数情况下这是有意义的,但其他人可能不同意。

回答by Jixian Wang

its ordered by function names letter orders, doesn't matter how you order it in your code. e.g.:

它按函数名称字母顺序排序,与您在代码中如何排序无关。例如:

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

the actual execute order is :

实际执行顺序是:

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

回答by basvk

In addition to andrew-madsen's answer:
I created a 'smart' testInvocationsclass method which searches for selectors starting with "test" and sorts them alphabetically.
So you don't have to maintain an NSArrayof selector names separately.

除了andrew-madsen的回答:
我创建了一个“智能”testInvocations类方法,它搜索以“test”开头的选择器并按字母顺序对它们进行排序。
所以你不必NSArray单独维护一个of 选择器名称。

#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

脚注:让你的单元测试相互依赖被认为是不好的做法

回答by ant_one

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 使用字母顺序处理文件。

回答by 0xced

Since Xcode 7, XCTestCase subclasses are alphabetically ordered. If you want to ensure that the test methods themselves are also run in alphabetical order, you must override the testInvocationsclass method and return the invocations sorted by selector.

从 Xcode 7 开始, XCTestCase 子类按字母顺序排列。如果要确保测试方法本身也按字母顺序运行,则必须覆盖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

回答by AnneTheAgile

The OP did not mention whether CI is available or whether a command line answer would be sufficient. In those cases, I have enjoyed using xctool [1]. It has syntax to run tests down to just a single test method:

OP 没有提到 CI 是否可用或命令行答案是否足够。在这些情况下,我喜欢使用 xctool [1]。它具有将测试运行到单个测试方法的语法:

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. ; ; https://github.com/facebook/xctool

1.[] facebook/xctool:Apple 的 xcodebuild 的替代品,可以更轻松地构建和测试 iOS 或 OSX 应用程序。; ; https://github.com/facebook/xctool