Comment détecter si l'application iOS s'exécute en mode de test de l'interface user

Je voudrais que mon application exécute un code spécial (par exemple en réinitialisant son état) lors de l'exécution en mode de test de l'interface user. J'ai regardé les variables d'environnement qui sont définies lorsque l'application est exécutée à partir du test de l'interface user et il n'y a pas de parameters évidents pour différencier l'application qui s'exécute normalement par rapport au test d'interface user. Y a-t-il un moyen de le savoir?

Deux solutions de contournement dont je ne suis pas satisfait sont:

  1. Définissez XCUIApplication.launchEnvironment avec une variable que je vérifie plus tard dans l'application. Ce n'est pas bon parce que vous devez le définir dans la méthode setUp de chaque file de test. J'ai essayé de définir la variable d'environnement à partir des parameters du système, mais cela ne se propage pas à l'application elle-même lors de l'exécution des tests de test de l'interface user.
  2. Vérifiez le manque d'existence de la variable d'environnement __XPC_DYLD_LIBRARY_PATH . Cela semble très hacky et pourrait seulement fonctionner maintenant en raison d'une coïncidence dans la façon dont nous avons mis en place nos parameters de construction cible.

J'ai fait des searchs moi-même et suis tombé sur cette question. J'ai fini par aller avec la première solution de contournement de @ LironYahdav:

Dans votre test d'interface user:

 - (void)setUp { [super setUp]; XCUIApplication *app = [[XCUIApplication alloc] init]; app.launchEnvironment = @{@"isUITest": @YES}; [app launch]; } 

Dans votre application:

 NSDictionary *environment = [[NSProcessInfo processInfo] environment]; if (environment[@"isUITest"]) { // Running in a UI test } 

@ Les solutions de JoeMasilotti sont utiles pour les tests unitaires , car elles partagent le même environnement d'exécution que l'application testée, mais ne sont pas pertinentes pour les tests d'interface user.

Vous pouvez utiliser des macros de préprocesseur pour cela. J'ai trouvé que vous avez deux choix:

Nouvelle cible

Faites une copy de la cible de l'application et utilisez-la comme cible à tester . Toute macro de préprocesseur dans cette copy cible est accessible en code.

Un inconvénient est que vous devrez append de nouvelles classs / ressources à la cible de copy et parfois très facile à oublier.

Nouvelle configuration de construction

Faites une copy de la configuration de construction de debugging , définissez n'importe quelle macro de préprocesseur sur cette configuration et utilisez-la pour votre test (voir les captures d'écran ci-dessous).

Un problème mineur: chaque fois que vous voulez save une session de test d'interface user, vous devez modifier l' exécution pour utiliser la nouvelle configuration de test.

Ajouter une configuration en double:

Ajouter un doublon conf

Utilisez-le pour votre test :

Utilisez-le pour votre * Test *

Je n'ai pas réussi à définir un environnement de lancement, mais je l'ai fait fonctionner avec des arguments de lancement.

Dans vos tests, la fonction setUp () ajoute:

  let app = XCUIApplication() app.launchArguments = ["testMode"] app.launch() 

Dans votre code de production, ajoutez une vérification comme:

 let testMode = NSProcessInfo.processInfo().arguments.contains("testMode") if testMode { // Do stuff } 

Vérifié en utilisant XCode 7.1.1.

Je viens d'append cette extension

  @available(iOS 9, *) extension XCUIApplication { func test(){ launchEnvironment = ["TEST":"true"] launch() } } 

Je peux donc simplement utiliser test () au lieu de launch ()

Dans Swift 3, vous pouvez vérifier la key XCInjectBundleInto ou quelque chose qui commence par XC .

 let isInTestMode = ProcessInfo.processInfo.environment["XCInjectBundleInto"] != nil 

Cela fonctionne également sous OS X.

Swift 3 basé sur les réponses précédentes.

 class YourApplicationUITests: XCTestCase { override func setUp() { super.setUp() // Put setup code here. This method is called before the invocation of each test method in the class. // In UI tests it is usually best to stop immediately when a failure occurs. continueAfterFailure = false // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. let app = XCUIApplication() app.launchArguments = ["testMode"] app.launch() // In UI tests it's important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. } override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() } func testExample() { // Use recording to get started writing UI tests. // Use XCTAssert and related functions to verify your tests produce the correct results. } } extension UIApplication { public static var isRunningTest: Bool { return ProcessInfo().arguments.contains("testMode") } } 

Ensuite, appelez simplement UIApplication.isRunningTest dans votre code.

Je pense que la chose la plus facile à faire est de mettre une sorte d'oeuf de pâques dans votre interface user juste après le lancement de l'application et ensuite vérifier pour cet oeuf de Pâques dans l'application. Donc, si vous tapez sur un certain button 10X en premier, cela définira un paramètre user ou une variable d'environnement ou quoi que ce soit qui peut ensuite être vérifié dans l'application. Cela semble un peu hacky mais je ne pouvais pas find d'autre moyen de le faire.

Les deux process ont leurs propres sets de variables d'environnement, de parameters par défaut et d'options de lancement.