Xcode 7 essais avec L'interface utilisateur localisée
Dans mon Application j'utilise NSLocalizedString
localiser mon application. Maintenant je veux passer à UITests
et habe Testcode comme ceci:
[tabBarsQuery.buttons["particiants"] tap];
cela fonctionne pour l'anglais mais ne fonctionne pas pour les autres langues.
[tabBarsQuery.buttons[NSLocalizedString("PARTICIPANTS",comment:nil)] tap];
échoue-probablement parce que localisable.strings est dans un autre paquet. Comment tester une application localisée?
9 réponses
je voulais tester le contenu des fonctionnalités de L'interface utilisateur et pas seulement leur existence, donc définir un langage par défaut ou utiliser les identificateurs d'accessibilité ne conviendrait pas.
cela s'appuie sur Volodymyr 's et matsoftware 's answers. Cependant, leurs réponses s'appuient sur deviceLanguage
qui doit être explicitement défini dans SnapshotHelper
. Cette solution obtient de façon dynamique le langage pris en charge que le périphérique utilise.
- ajoutez les fichiers
Localizable.strings
à votre cible UITest. -
ajouter le code suivant à votre cible UITest:
var currentLanguage: (langCode: String, localeCode: String)? { let currentLocale = Locale(identifier: Locale.preferredLanguages.first!) guard let langCode = currentLocale.languageCode else { return nil } var localeCode = langCode if let scriptCode = currentLocale.scriptCode { localeCode = "\(langCode)-\(scriptCode)" } else if let regionCode = currentLocale.regionCode { localeCode = "\(langCode)-\(regionCode)" } return (langCode, localeCode) } func localizedString(_ key: String) -> String { let testBundle = Bundle(for: /* a class in your test bundle */.self) if let currentLanguage = currentLanguage, let testBundlePath = testBundle.path(forResource: currentLanguage.localeCode, ofType: "lproj") ?? testBundle.path(forResource: currentLanguage.langCode, ofType: "lproj"), let localizedBundle = Bundle(path: testBundlePath) { return NSLocalizedString(key, bundle: localizedBundle, comment: "") } return "?" }
-
accéder à la méthode par
localizedString(key)
pour les langues avec un code de script, le localeCode
sera langCode-scriptCode
(par exemple, zh-Hans
). Autrement le localeCode
sera langCode-regionCode
(par exemple, pt-BR
). Le testBundle
essaie d'abord de résoudre le lproj par localeCode
, puis retombe juste langCode
.
S'il ne peut toujours pas obtenir le paquet, il retourne "?"pour la chaîne, donc il échouera tous les tests D'interface utilisateur qui cherchent des chaînes spécifiques.
Option 1: Définir une langue par défaut
créer un nouveau schéma pour le test D'interface utilisateur et définir le langage d'Application par défaut. Cela va verrouiller l'application dans un fichier localisé afin que vous puissiez écrire tous vos tests pour cette langue.
définir L'option du produit - > schéma - > Gérer les schémas ou ⌘⇧, . Ensuite, sélectionnez l'onglet Options et choisir la langue.
Pros : Simple, un changement de temps.
Cons : ne peut pas être utilisé pour créer des captures d'écran localisées avec snapshot (un outil qui exécute votre application via un test D'interface utilisateur et génère des captures D'écran de boutique D'applications le long du chemin).
Option 2: Utiliser -accessibilityIdentifier
pour les chaînes localisées
au lieu d'accéder aux articles via leur affichage texte ou valeur, utilisez accessibilityIdentifier
. Ceci est lu par le cadre de test de L'UI mais jamais montré ou lu aux utilisateurs (même avec l'accessibilité activée). Dans L'ancienne UIAutomation Docs Apple mentionne l'utilisation de cette fonctionnalité pour les développeurs, ce qui se présente comme un bon cas d'utilisation.
vous pouvez alors continuer à définir accessibilityLabel
et accessibilityValue
comme normal, avec les versions localisées.
Pros : peut être utilisé pour des solutions plus génériques, comme prendre des captures d'écran automatisées.
Cons : peut nécessiter plus de travail changer chaque étiquette dont vous avez besoin "non localisé" pour les tests.
VOUS POUVEZ RÉUTILISER VOS FAISCEAUX DE LOCALISATION DE PROJET!
lorsque vous testez le comportement des boîtes à messages, vous devez savoir exactement quelle boîte à messages vient d'apparaître. Vous devez copier votre localisation à partir d'un autre schéma pendant la phase de construction.
dans vos tests D'interface utilisateur target - > Build Phases - > Copy Bundle Resources, add the localization files neededed (e.g. localisable.chaîne.)
Ajouter une fonction similaire à la
func localizedString (key: String) - > String {
/*1*/ laissez localizationBundle = NSBundle(chemin d'accès: NSBundle(forClass: /*2 UITestsClass*/.auto.)pathForResource (deviceLanguage, ofType: "lproj")!)
/*3*/ laissez résultat = NSLocalizedString(clé, bundle:localizationBundle!, commentaire: "") //
résultat de retour
}
/*1 obtient le paquet correct pour le fichier de localisation, voir ici: /q/peut-t-get-access-to-string-localisations-en-ui-test-xcode-7-23891/"localisée.chaîne.la clé")]
article complet est ici: https://github.com/fastlane-old/snapshot/issues/321#issuecomment-159660882
la manière la plus simple et fiable pour moi jusqu'à présent est de faire référence à des éléments avec elementBoundByIndex() Comme ceci:
let app = XCUIApplication()
let tabBar = app.tabBars
tabBar.buttons.elementBoundByIndex(2).tap()
app.navigationBars.buttons.elementBoundByIndex(0).tap()
app.tables.cells.elementBoundByIndex(2).tap()
app.tables.elementBoundByIndex(1).cells.elementBoundByIndex(0).tap()
vous pouvez deviner/expérimenter avec ces valeurs et trouver les éléments dont vous avez besoin.
la réponse de Volodymyr m'a beaucoup aidé, mais elle peut échouer si le nom du dossier du paquet de localisation diffère du devicelanguage défini dans Snapshot. Cet extrait fonctionne très bien pour moi dans Swift 3.0 et avec des langues comme l'italien (où le local actuel est "it" mais le langage de périphérique est "it-IT").
func localizedString(key:String) -> String {
let languageBundlePath = Bundle(for: PlinthUITests.self).path(forResource: deviceLanguage, ofType: "lproj") ?? Bundle(for: PlinthUITests.self).path(forResource: NSLocale.current.languageCode!, ofType: "lproj")
let localizationBundle = Bundle(path: languageBundlePath!)
let result = NSLocalizedString(key, bundle:localizationBundle!, comment: "")
return result
}
si vous faites cela dans le but de lancer Snapshot (plutôt que L'UI test), alors je trouve la solution la plus simple est de tricher et d'utiliser HSTestingBackchannel 151930920"
c'est un outil que j'ai écrit qui vous permet d'envoyer des notifications de la classe UITesting à l'application. Ensuite, vous écrivez du code dans l'application qui répond directement aux notifications.
en plus de la réponse de Joe, vous pouvez aussi forcer le langage pour les tests D'UI directement dans le code de test sans éditer un schéma comme celui-ci:
- (void)setUp
{
[super setUp];
self.continueAfterFailure = NO;
XCUIApplication *app = [[XCUIApplication alloc] init];
app.launchArguments = @[@"-AppleLanguages", @"(en)", @"-AppleLocale", @"en_EN"];
[app launch];
}
la réponse de SeanR est grande (+1), mais il y a une amélioration mineure:
si vous utilisez la localisation de base, alors votre Localizable.strings
pourrait ne pas être localisé dans votre langue de base. Cela n'est pas nécessaire car la langue de base serait utilisée dans ce cas. Si c'est le cas, la fonction de SeanR localizedString
renvoie „?“
.
la version étendue ci-dessous vérifie en plus pour la langue de base, et renvoie la chaîne localisée dans la base langue:
func localizedString(_ key: String) -> String {
let testBundle = Bundle(for: ShopEasyUITests.self)
guard let currentLanguage = currentLanguage else { return "?" }
if let testBundlePath = testBundle.path(forResource: currentLanguage.localeCode, ofType: "lproj"),
let localizedBundle = Bundle(path: testBundlePath) {
return NSLocalizedString(key, bundle: localizedBundle, comment: "")
}
if let testBundlePath = testBundle.path(forResource: currentLanguage.langCode, ofType: "lproj"),
let localizedBundle = Bundle(path: testBundlePath) {
return NSLocalizedString(key, bundle: localizedBundle, comment: "")
}
if let testBundlePath = testBundle.path(forResource: "Base", ofType: "lproj"),
let localizedBundle = Bundle(path: testBundlePath) {
return NSLocalizedString(key, bundle: localizedBundle, comment: "")
}
return "?"
}
pour la fonction snapshot de fastlane, le SnapshotHelper.swift
lance l'application avec ces arguments. Ainsi, en interprétant ces valeurs, Cette solution est déterministe, et j'ai pu produire des instantanés corrects pour plusieurs langues:
func getLocale(str: String) -> String {
let start = str.index(str.startIndex, offsetBy: 1)
let end = str.index(start, offsetBy: 2)
let range = start..<end
var locale = str.substring(with: range)
if locale == "en" {
return "Base"
}
return locale
}
func localizedString(_ key: String) -> String {
print("app.launchArguments \(app.launchArguments)")
guard let localeArgIdx = app.launchArguments.index(of: "-AppleLocale") else {
return ""
}
if localeArgIdx >= app.launchArguments.count {
return ""
}
let str = app.launchArguments[localeArgIdx + 1]
let locale = getLocale(str: str)
let testBundle = Bundle(for: Snapshot.self)
if let testBundlePath = testBundle.path(forResource: locale, ofType: "lproj") ?? testBundle.path(forResource: locale, ofType: "lproj"),
let localizedBundle = Bundle(path: testBundlePath)
{
return NSLocalizedString(key, bundle: localizedBundle, comment: "")
}
return ""
}
Espérons que cette aide