具有本地化app.staticTexts的UI测试(XCTest)

亦余心之所善兮,虽九死其犹未悔。这篇文章主要讲述具有本地化app.staticTexts的UI测试(XCTest)相关的知识,希望能为你提供帮助。
我正在为我的应用程序编写UI测试,该应用程序使用UIWebView作为其内容。当按下webview中的按钮时,它会将测试用例写入如下:

func testExample() { let app = XCUIApplication() app.staticTexts["Log In"].tap() }

这里的问题是,如果应用程序处于不同的本地化(例如“de-DE”),则不存在具有文本“登录”的按钮。取而代之的是“Anmelden”。我尝试了以下内容,但它们都不起作用:
Localizable.strings版本:
func testExample() { let name = NSLocalizedString("Log In", comment: "")let app = XCUIApplication() app.staticTexts[name].tap() }


public class Titles { var homeScreenLogIn = "Log In" }public class TitlesDE: Titles {override init() { super.init()homeScreenLogIn = "Anmelden" }}

...
func testExample() { titles = TitlesDE()let name = titles.homeScreenLogInlet app = XCUIApplication() app.staticTexts[name].tap() }

UI测试失败 - 找到多个匹配项:
【具有本地化app.staticTexts的UI测试(XCTest)】问题是我似乎无法弄清楚如何将数据转储到调试/测试输出,因为print()似乎不起作用。
答案您应该使用所有accessibilityIdentifier对象都具有的UIKit属性,因为此字符串未本地化,它仅用于UI自动化。
也就是说,当你使用UIWebView的内容时,似乎没有一个简单的解决方案。
另一答案这是我的解决方案,我将字符串对象扩展为包含.localized()...您可以忽略(或更改)所有bundleName逻辑,因为它特定于我的项目,其中shell脚本移动/重命名本地化包非常具体的方式,但基本上,您需要从设备的当前设置语言中获取软件包的目录名称。还要注意,要使这项工作,我必须添加到我的UI测试目标“复制捆绑资源”应用程序的Localizable.strings和Localizable.stringsdict
使用案例:app.buttons [“Tap Me!”。localized()]。tap()app.staticTexts [“在App中显示的本地化字符串值”] .tw()
请记住,您调用.localized()的字符串必须在应用程序的Localizable包中定义,如果不是,那么它不是一个在设备语言更改时将转换的字符串。
extension String {
func localized() -> String {// all this shit with bundleName is here only because we have a shell script that // renames/moves all of our localization folders var bundleName:String = deviceLanguage.stringByReplacingOccurrencesOfString("_", withString: "-") let secondaryBundleNameParts = deviceLanguage.componentsSeparatedByString("-") let secondaryBundleNamePartOne = secondaryBundleNameParts[0] let secondaryBundleNamePartTwo = secondaryBundleNameParts.count > 1 ? secondaryBundleNameParts[1] : "" let thirdBundleName = "(secondaryBundleNamePartOne)-(secondaryBundleNamePartTwo.uppercaseString)" if secondaryBundleNamePartOne == "es" { bundleName = secondaryBundleNamePartTwo == "ES" ? "es" : thirdBundleName } else if secondaryBundleNamePartOne == "pt" { bundleName = secondaryBundleNamePartTwo == "BR" ? "pt" : thirdBundleName } else if secondaryBundleNamePartOne == "zh" { bundleName = secondaryBundleNamePartTwo == "CN" ? "zh-Hans" : "zh-Hant" } else { bundleName = secondaryBundleNamePartOne } var bundlePath:String? = NSBundle(forClass: FGUITestCase.self).pathForResource(bundleName, ofType: "lproj") if bundlePath == nil { bundlePath = NSBundle(forClass: FGUITestCase.self).pathForResource(deviceLanguage, ofType: "lproj") if bundlePath == nil { bundlePath = NSBundle(forClass: FGUITestCase.self).pathForResource(bundleName, ofType:nil) if bundlePath == nil { bundlePath = NSBundle(forClass: FGUITestCase.self).pathForResource(deviceLanguage, ofType:nil) if bundlePath == nil { for var i=0; i< 100; i++ { NSLog("OMG, WTF, Localization Bundle Not Found!: (bundleName) || (deviceLanguage)") print("OMG, WTF, Localization Bundle Not Found!: (bundleName) || (deviceLanguage)") } } } } }let bundle = NSBundle(path:bundlePath!) return NSLocalizedString(self, bundle:bundle!, comment: "") }subscript (i: Int) -> Character { return self[self.startIndex.advancedBy(i)] }subscript (i: Int) -> String { return String(self[i] as Character) }subscript (r: Range< Int> ) -> String { let start = startIndex.advancedBy(r.startIndex) let end = start.advancedBy(r.endIndex - r.startIndex) return self[Range(start: start, end: end)] }

}
另一答案我能够处理这个问题的方法是创建一个Localization类,它包含不同UI元素的翻译字典,可以使用String键提取,该键对应用程序中的Web视图元素是唯一的。
要使用的定位使用全局变量localization来设置,该变量可以在测试期间的任何点设置,例如,在setUp()期间。
使用枚举表示本地化。
注意:这是一个非常粗略的实现,因为在字典上验证的方式并不多 - 创建一个本地化集类并使用[String: LocalizedIdentifierSet]字典将是一个更可靠的解决方案。
var localization = .Germanyclass Localization {/// Dictionary containing localizations for each available localisation private static var localizations: [String: [Localization: String]] = [ "signOutLink": [ .UnitedKingdom: "SIGN OUT", .UnitedStates: "SIGN OUT", .France: "DéCONNEXION", .Germany: "ABMELDEN", .Italy: "ESCI", .Spain: "SALIR", .Australia: "SIGN OUT", .Russia: "ВЫЙТИ" ], "appSettingsLink": [ .UnitedKingdom: "App Settings", .UnitedStates: "App Settings", .France: "Réglages", .Germany: "App-Einstellungen", .Italy: "Impostazioni dell'App", .Spain: "Ajustes de la App", .Australia: "App Settings", .Russia: "Ajustes de la App" ] ]/** Returns a String containing the localized identifier for the element with the given `identifier`, for the currently-selected `localization`.- Parameter identifier: String identifier for the element you want to retrieve the localized query string for.- Returns: String to be used for querying the view hierarchy to find the element with `identifier`. */ class func getLocalizedQueryStringForElementWithIdentifier(identifier: String) -> String? { let localizationsForElement = localizations[identifier] let queryString = localizationsForElement?[localization] return queryString } }

然后,您可以使用此类检索您在查询中使用的标识符:
let textIdentifier = Localization.getLocalizedQueryStringForElementWithIdentifier("signOutLink") let textElement = app.staticTexts[textIdentifier!] textElement.tap()

另一答案我终于用测试函数中的代码实现了它:
let locale = Locale.current.identifier print(locale)var tap1 = "STRING OF UI TEST 1 in ENGLISH" var tap2 = "STRING OF UI TEST 2 in ENGLISH"if (locale == "fr_US" || locale == "fr" || locale == "fr_FR" || locale == "fr_CA") { tap1 = "STRING OF UI TEST 1 in FRENCH" tap2 = "STRING OF UI TEST 2 in FRENCH" } else if (locale == "es_US" || locale == "es_ES" || locale == "es") { tap1 = "STRING OF UI TEST 1 in SPANISH" tap2 = "STRING OF UI TEST 2 in SPANISH" }

只需在生成UITest的代码中,更改我们刚刚创建的变量的“字符串”(tap1和tap2)。
就我而言:
let textView = scrollViewsQuery.otherElements.containing(.staticText, identifier:tap1).children(matching: .textView).element

我在使用SWIFT 4。
希望能帮助到你 :)

    推荐阅读