web-dev-qa-db-fra.com

Comment migrer de SenTestingKit / OCUnit vers XCTest?

Je suis en train de migrer mon projet de Xcode 4.6.3 vers Xcode 5.0.2. Les tests unitaires du projet ont été développés avec SenTestingKit/OCUnit. Maintenant, lorsque j'exécute les tests dans Xcode 5, je reçois une erreur du script RunUnitTests me disant que

RunUnitTests est obsolète.

Peut-être liée à cette note dans les notes de version de Xcode 5:

SenTestingKit et OCUnit sont obsolètes. Utilisez le migrateur pour passer à XCTest.

Malheureusement, je n'ai pas pu en savoir plus sur ce mystérieux "migrateur". Peut-être que mon google-fu manque [encore], donc ma principale question est: comment migrer les tests unitaires de SenTestingKit/OCUnit vers le nouveau XCTest (avec ou sans le "migrateur")?

Une question secondaire, dans le cas où la migration est une entreprise compliquée: est-il possible d'obtenir Xcode 5 pour exécuter des tests unitaires qui sont toujours basés sur SenTestingKit/OCUnit? Après tout, ceux-ci sont simplement obsolètes, ils devraient donc toujours être présents et fonctionnels.

35
herzbube

Grâce à la réponse de Shaggy Frog, nous savons que le mystérieux "migrateur" mentionné dans les notes de publication de Xcode est un assistant lancé en sélectionnant "Modifier> Refactor> Convertir en XCTest". Je vais écrire mon expérience avec cet assistant en deux parties. La première partie est une réponse incomplète à la question principale, la deuxième partie répond à la question secondaire.


Partie 1: Comment migrer d'OCUnit vers XCTest

La première chose que vous devez comprendre est que pour que l'assistant fonctionne, vous devez sélectionner une cible de test unitaire. Si vous avez sélectionné la cible principale, l'assistant ne répertorie tout simplement aucune cible à convertir.

Une fois que j'ai découvert cela, j'ai pu traverser l'assistant, mais dans mon cas, le résultat final a toujours été un échec spectaculaire! L'assistant a affirmé qu'aucune modification de source n'était nécessaire et que seuls les paramètres de génération devaient être mis à jour pour migrer vers XCTest. En fin de compte, l'assistant n'a même pas réussi à le faire correctement: il l'a fait a supprimé la référence au framework SenTestingKit, mais il a pas mis dans un référence au cadre XCTest.

Quoi qu'il en soit, ce qui suit est une liste des modifications que j'ai dû apporter manuellement car l'assistant n'a pas réussi à les effectuer pour moi. Si l'assistant fonctionne mieux pour vous, vous n'aurez peut-être pas besoin de faire toutes ces choses.

  1. Supprimez la phase de construction "Exécuter le script" de la cible de test unitaire
  2. Modifiez la classe de base de toutes les classes de cas de test de SenTestCase à XCTestCase
  3. Changez l'en-tête importé de <SenTestingKit/SenTestingKit.h> En <XCTest/XCTest.h>
  4. Dans les paramètres de génération de la cible de test, changez l'extension de wrapper de octest à xctest.
  5. Renommez toutes les macros d'assertion de ST* En XCT* (Par exemple STAssertTrue devient XCTAssertTrue)
  6. Exception à ce qui précède: STAssertEquals doit être renommé XCTAssertEqual (notez les "s" manquants à la fin). Vous saurez que vous avez oublié cela si vous obtenez cet avertissement du compilateur: warning: implicit declaration of function 'XCTAssertEquals' is invalid in C99
  7. Les nouvelles macros d'assertion XCTest n'autorisent pas le passage de nil comme description de l'échec. Par exemple, XCTAssertNotNil(anObject, nil) n'est pas possible et doit être remplacé par XCTAssertNotNil(anObject). Vous saurez que vous rencontrez ce problème lorsque vous obtenez cette erreur de compilation: error: called object type 'NSString *' is not a function or function pointer.
  8. Si vous faites devez passer une description d'échec, les nouvelles macros d'assertion XCTest nécessitent une expression constante pour le spécificateur de format, tout comme la méthode de classe NSStringstringWithFormat: Est-ce que. Vous saurez que vous rencontrez ce problème lorsque vous obtenez cette erreur de compilation: error: expected ')'. Quelques exemples:
NSString* formatSpecifier = @"%@";
NSString* failureDescription = @"foo";
// These are OK
XCTAssertNotNil(anObject, @"foo")
XCTAssertNotNil(anObject, @"%@", failureDescription)
// These are not OK
XCTAssertNotNil(anObject, failureDescription);
XCTAssertNotNil(anObject, formatSpecifier, failureDescription);

Enfin et surtout, comme déjà mentionné plus haut, la référence au cadre XCTest doit être ajoutée à la cible de test unitaire. Vous saurez que vous l'avez oublié si vous obtenez des erreurs de l'éditeur de liens telles que Undefined symbols for architecture i386: "_OBJC_CLASS_$_XCTestCase", referenced from: foo.

Mise à jour de Xcode 6 : La liaison avec XCTest n'est plus requise dans Xcode 6 (en fait, XCTest n'est même plus répertorié en tant que framework disponible). Au lieu de cela, définissez le paramètre de génération CLANG_ENABLE_MODULES sur YES (exposé dans l'interface utilisateur comme "Activer les modules (C et Objective-C)"). Cela entraînera la liaison automatique de clang avec XCTest lorsqu'il verra une instruction #import <XCTest/XCTest.h>. Les détails sont disponibles dans la section "Modules" de la documentation de clang .


Partie 2: Comment exécuter les tests OCUnit dans Xcode 5

À ce stade, j'ai eu une erreur de l'éditeur de liens qui m'a fait réaliser que ma mission de migrer vers XCTest avait échoué. La raison: XCTest ne fait pas partie du SDK 6.1, mais je construis toujours mon projet avec le SDK de base iOS 6.1 ( this SO answer explique comment intégrer SDK 6.1 dans Xcode 5).

Étant donné que je ne peux pas continuer la migration, ma solution pour le moment est donc de conserver mes tests unitaires basés sur SenTestingKit/OCUnit, jusqu'à ce que je trouve le temps de mettre à jour mon application vers iOS 7. C'est ce que j'ai dû faire pour pour exécuter les tests unitaires:

  1. Supprimez la phase de construction "Exécuter le script" de la cible de test unitaire. C'est tout ce qui est nécessaire pour laisser Xcode exécuter des tests unitaires via l'action "Test" (U) lorsque la cible de test unitaire est sélectionnée.
  2. Ce n'est pas idéal, cependant, car je ne veux pas changer de cible uniquement pour exécuter des tests unitaires. Au lieu de cela, je veux exécuter des tests unitaires alors que la cible principale est sélectionnée. La deuxième étape consiste donc à modifier le schéma Xcode de la cible principale de sorte que lorsque j'exécute l'action "Test", les tests de la cible de test unitaire soient exécutés à la place.

La solution finale n'est pas aussi bonne que dans Xcode 4.x où les tests unitaires ont été exécutés automatiquement chaque fois que j'ai exécuté l'action "Exécuter" ou "Construire" de la cible principale. Malheureusement, il semble que je ne puisse pas faire fonctionner cela sans une phase de construction "Run Script".

59
herzbube

Modifier -> Refactor -> Convertir en XCTest

Les tests OCUnit fonctionneront toujours, mais vous pourriez aussi bien migrer. Les changements finissent par être assez minimes.

14
Shaggy Frog