Подтвердить что ты не робот

Заказ unit test с использованием XCTest в Xcode 6

Я хотел бы знать, есть ли способ сказать Xcode для запуска модульных тестов в указанном порядке. Я имею в виду не в том же файле класса XCTestCase, а между всем файлом класса.

enter image description here

Например, я хочу запустить SitchozrSDKSessionTest перед запуском SitchozrSDKMessageTest.

Я просмотрел несколько потоков в стеке или документацию Apple, и я не нашел что-то полезное.

Спасибо за вашу помощь.

4b9b3361

Ответ 1

Все они отсортированы по алфавиту (классы и методы). Поэтому, когда вам нужны некоторые тесты, выполняемые последними, просто измените имя класса или метода (для (скверного) примера с помощью префикса "z _" ).

Итак... У вас есть имена классов:

MyAppTest1
  -testMethodA
  -testMethodB
MyAppTest2
  -testMethodC
  -testMethodD

и они выполняются в этом порядке. Если вам нужно запустить MyAppTest1 как второй, просто переименуйте его так, чтобы оно было в алфавитном порядке после MyAppTest2 (z_MyAppTest1), и оно будет работать (одинаково для метода):

MyAppTest2
  -a_testMethodD
  -testMethodC
z_MyAppTest1
  -testMethodA
  -testMethodB

Также, пожалуйста, возьмите именование в качестве примера:)

Ответ 2

Верно, что в настоящее время (с Xcode 7) методы XCTestCase выполняются в алфавитном порядке, поэтому вы можете заставить их порядок, называя их умным способом. Однако это детализация реализации и кажется, что она может измениться.

A (надеюсь) менее хрупкий способ сделать это - переопределить +[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;
}

Конечно, недостатком здесь является то, что вам нужно вручную добавить каждый тестовый метод к этому, вместо того, чтобы автоматически их подбирать. Есть несколько способов улучшить эту ситуацию. Если вам нужно всего лишь заказать некоторые из ваших методов тестирования, но не все из них, при переопределении +testInvocations, вы можете вызвать супер, отфильтровать те методы, которые вы вручную заказывали, а затем отложить остальные на конец возвращаемого массива. Если вам нужно заказать все методы тестирования, вы все равно можете получить результат вызова супер и убедитесь, что все автоматически выбранные методы покрываются созданным вручную упорядоченным результатом. Если нет, вы можете утверждать, что это приводит к сбою, если вы забыли добавить какие-либо методы.

Я оставляю в стороне обсуждение вопроса о том, "правильно ли" писать тесты, которые должны выполняться в определенном порядке. Я думаю, что есть редкие сценарии, где это имеет смысл, но другие могут не согласиться.

Ответ 3

его упорядоченные по именам букв имен функций, не имеет значения, как вы заказываете его в своем коде. например:.

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

фактический порядок выполнения:

  • testB1Fun называется
  • testB2Fun называется
  • testCFun называется

Ответ 4

В дополнение к andrew-madsen ответ:
Я создал метод "умный" 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;
}

Сноска: он считал плохую практику, которая заставляла ваши модульные тесты зависеть от друг друга.

Ответ 5

Например, вы можете просто переименовать файлы тестов в свой проект следующим образом:

SitchozrSDKSessionTest -> t001_SitchozrSDKSessionTest
SitchozrSDKMessageTest -> t002_SitchozrSDKMessageTest

Xcode обрабатывает файлы, используя алфавитный порядок.

Ответ 6

OP не упоминает, доступен ли CI или достаточно ответа в командной строке. В таких случаях мне нравилось использовать xctool [1]. Он имеет синтаксис для запуска тестов вплоть до одного тестового метода:

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

Я сделаю это, чтобы убедиться, что мы тестируем элементы, которые мы считаем самыми легкими в первую очередь.

1. [] facebook/xctool: замена для Apple xcodebuild, которая упрощает сборку и тестирование приложений для iOS или OSX.;; https://github.com/facebook/xctool

Ответ 7

Так как 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