2015-12-17 1 views
25

Я пытаюсь включить тесты пользовательского интерфейса в свой проект iOS, но одна вещь, которая продолжает меня удерживать, - это то, что, похоже, все тесты, которые вы пишете, должны начинаться с начала приложение и прокладывать себе путь. Например, если я хочу протестировать представление, которое находится за экраном входа, мои тесты должны сначала запускаться на экране входа в систему, ввести имя пользователя/пароль, щелкнуть логин, а затем перейти к представлению, которое я хочу проверить. В идеале тесты для входа в систему и следующего будут полностью изолированы. Есть ли способ сделать это, или я полностью лишу философии тестов UI?iOS UI Testing On Isolated View

+0

Я действительно очень хочу, чтобы это работало хорошо ly: приложение начинает чист, тестовый код решает, как представить VC, а тестовый код использует Automation для взаимодействия с пользовательским интерфейсом. Это UI Unit Testing. Все мои исследования по этой теме приведены здесь https://gist.github.com/fulldecent/529849bc5dd4464bbde2, может быть, кто-то еще может забрать факел. –

ответ

-1

К сожалению, при тестировании пользовательского интерфейса сценарий, который вы описываете, невозможен.

Один из подходов, который я принимаю для борьбы с этим, заключается в том, чтобы сгруппировать мои тесты в «потоки» функций. Например, допустим, я хочу протестировать функцию A, функцию B и функцию C. Мне нужно войти в систему, чтобы все три работали.

Для каждого теста я не запускаю приложение, войдите в систему, а затем, наконец, запустите фактический тест. Вместо этого я запускаю приложение и вхожу один раз. Затем я группирую свой тест на три частных вспомогательных метода: testFeatureA(), testFeatureB() и testFeatureC().

Создав один поток, набор тестов займет гораздо меньше времени. Большой недостаток заключается в том, что если функция A не работает, функция B никогда не будет проверена. Этот подход следует использовать только в том случае, если вам нужно, чтобы прошел все тесты.

Бонусные баллы за использование XCTest helper с параметрами __LINE__ и __FILE__ по умолчанию. Затем вы можете передать их в свои вызовы XCTFail(), чтобы показать строку сбоя на testFeatureA().

+0

Вниз, насколько это возможно (см. Quellish ответ) –

19

Абсолютно!

Что вам нужно - это чистая среда приложения, в которой вы можете запускать свои тесты - чистый лист.

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

Для этого вы можете создать объект только для тестирования, который реализует UIApplicationDelegate. Вы можете сказать, что приложение запускается в «режиме тестирования» и использует делегат приложения для тестирования, используя аргумент запуска.

Objective-C: main.m:

int main(int argc, char * argv[]) { 
NSString * const kUITestingLaunchArgument = @"org.quellish.UITestingEnabled"; 

    @autoreleasepool { 
     if ([[NSUserDefaults standardUserDefaults] valueForKey:kUITestingLaunchArgument] != nil){ 
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([TestingApplicationDelegate class])); 
     } else { 
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([ProductionApplicationDelegate class])); 
     } 
    } 
} 

Swift: main.swift:

let kUITestingLaunchArgument = "org.quellish.UITestingEnabled" 

if (NSUserDefaults.standardUserDefaults().valueForKey(kUITestingLaunchArgument) != nil){ 
    UIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(UIApplication), NSStringFromClass(TestingApplicationDelegate)) 

} else { 
    UIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(UIApplication), NSStringFromClass(AppDelegate)) 
} 

Вы должны удалить любой @UIApplicationMain аннотацию из ваших Swift классов.

Для «тестов приложений» быть уверены, чтобы установить «Test» действие схемы в Xcode, чтобы обеспечить запуск аргумент:

Xcode Scheme editor

Для тестирования пользовательского интерфейса можно установить аргументы запуска в рамках тест:

Objective-C:

XCUIApplication *app = [[XCUIApplication alloc] init]; 
[app setLaunchArguments:@[@"org.quellish.UITestingEnabled"] ]; 
[app launch]; 

Свифта:

let app = XCUIApplication() 
app.launchArguments = [ "org.quellish.UITestingEnabled" ] 
app.launch() 

Это позволяет испытаниям использовать делегат приложения специально для тестирования. Это наделяет вас большим контролем - теперь у вас есть пустой сланец для работы. Делегат приложения-тестировщика может загрузить конкретную раскадровку или установить пустой UIViewController. В рамках ваших тестов пользовательского интерфейса вы можете создать экземпляр контрольного контроллера просмотра и установить его в качестве контроллера корневого представления или представить его в виде модально. После того, как он будет добавлен или представлен, ваши тесты могут быть выполнены, и когда они будут удалены или отменены.

+4

Это решение кажется действительно приятным! Однако «NSUserDefaults.standardUserDefaults(). ValueForKey (kUITestingLaunchArgument)! = Nil 'не работал для меня. Я изменил его на NSProcessInfo.processInfo(). Arguments.contains (kUITestingLaunchArgument), чтобы заставить его работать. –

+0

@FyodorVolchyok Я бы настоятельно рекомендовал подавать радар, поскольку пользовательские настройки по умолчанию должны работать. Аргументы запуска заменяют другие значения по умолчанию, поскольку они находятся в домене аргументов. – quellish

+0

@quellish Вы не можете легко загрузить UIStoryboard в тесте (если вы не открываете приватный var, как в своем сообщении http://quellish.tumblr.com/post/135415677047/ios-application-and-ui-testing-in-isolation). Я использую дополнительные аргументы, поэтому TestAppDelegate знает, что UIStoryboard и UIViewController должны создавать экземпляр. –

4

Если вы не возражаете оригинальную загрузку пользовательского интерфейса, просто перейти к целевой UI с:

override func setUp() { 
    super.setUp() 
    continueAfterFailure = false 
    XCUIApplication().launch() 
    let storyboard = UIStoryboard(name: "MainStoryboard", bundle: NSBundle.mainBundle()) 
    let controller = storyboard.instantiateViewControllerWithIdentifier("LanguageSelectController") 
    UIApplication.sharedApplication().keyWindow?.rootViewController = controller 
} 

Если вы не хотите, оригинальный интерфейс внизу, чтобы загрузить затем также пройти в этом из теста:

app.launchArguments.append("skipEntryViewController") 

, а затем в didFinishLaunchingWithOptions, вы можете проверить:

if NSProcessInfo.processInfo().arguments.contains("skipEntryViewController") { 
    // then do NOT call makeKeyAndVisible 
} 
+0

Вопрос указывает, что необходимо чистое и изолированное тестирование, это не так. –

+0

Как это не соответствует этому требованию? –

+0

Сохранение одного и того же делегата приложения и загрузка оригинального пользовательского интерфейса может выполнять некоторую работу, которая может мешать. –

 Смежные вопросы

  • Нет связанных вопросов^_^