Ordering unit test using XCTest in Xcode 6

后端 未结 7 1361
眼角桃花
眼角桃花 2020-12-24 12:37

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.

相关标签:
7条回答
  • 2020-12-24 13:15

    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
    0 讨论(0)
  • 2020-12-24 13:20

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

    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):

    MyAppTest2
      -a_testMethodD
      -testMethodC
    z_MyAppTest1
      -testMethodA
      -testMethodB
    

    Also please take the naming as example :)

    0 讨论(0)
  • 2020-12-24 13:22

    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.
    So you don't have to maintain an NSArray of selector names separately.

    #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

    0 讨论(0)
  • 2020-12-24 13:23

    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 testInvocations class method and return the invocations sorted by selector.

    @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
    
    0 讨论(0)
  • 2020-12-24 13:25

    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.

    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.

    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. 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.

    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.

    0 讨论(0)
  • 2020-12-24 13:25

    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.

    0 讨论(0)
提交回复
热议问题