Ios 带有本地化UI的Xcode 7 UI测试
在我的应用程序中,我正在使用Ios 带有本地化UI的Xcode 7 UI测试,ios,swift,xcode7,xcode-ui-testing,Ios,Swift,Xcode7,Xcode Ui Testing,在我的应用程序中,我正在使用NSLocalizedString对我的应用程序进行本地化。现在我想切换到UITests,并使用如下测试代码: [tabBarsQuery.buttons["particiants"] tap]; - (void)setUp { [super setUp]; self.continueAfterFailure = NO; XCUIApplication *app = [[XCUIApplication alloc] in
NSLocalizedString
对我的应用程序进行本地化。现在我想切换到UITests
,并使用如下测试代码:
[tabBarsQuery.buttons["particiants"] tap];
- (void)setUp
{
[super setUp];
self.continueAfterFailure = NO;
XCUIApplication *app = [[XCUIApplication alloc] init];
app.launchArguments = @[@"-AppleLanguages", @"(en)", @"-AppleLocale", @"en_EN"];
[app launch];
}
这适用于英语,但不适用于其他语言
[tabBarsQuery.buttons[NSLocalizedString("PARTICIPANTS",comment:nil)] tap];
失败-可能是因为Localizable.strings位于另一个捆绑包中。如何测试本地化应用程序?选项1:设置默认语言
创建新的UI测试方案并设置默认应用程序语言。这会将应用程序锁定到一个本地化文件中,以便您可以为该语言编写所有测试
从产品->方案->管理方案或⌘⇧,. 然后选择选项选项卡并设置语言
优点:简单的一次性更改
缺点:无法使用(通过UI测试运行应用程序并生成应用商店屏幕截图的工具)创建本地化屏幕截图
选项2:对本地化字符串使用-accessibilityIdentifier
使用accessibilityIdentifier
,而不是通过显示的文本或值访问项目。这由UI测试框架读取,但从未向用户显示或读取(即使启用了可访问性)。在旧的UIAutomation文档中,苹果提到将此用于开发人员功能,这是一个很好的用例
然后,您可以继续使用本地化版本设置accessibilityLabel
和accessibilityValue
与普通设置一样
优点:可用于更通用的解决方案,如自动截图
缺点:可能需要更多的工作来更改每个需要“未定位”以进行测试的标签。到目前为止,我最简单可靠的方法是使用elementBoundByIndex()引用元素 像这样:
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()
您可以猜测/试验这些值,并找到您需要的元素。如果您这样做是为了运行快照(而不是实际的UI测试),那么我发现最简单的解决方案是欺骗和使用
这是我编写的一个工具,它允许您从UITesting类向应用程序发送通知。然后在应用程序中编写代码,直接响应通知。您可以重新使用项目本地化包强> 当您测试消息框行为时,您需要确切地知道刚刚出现的消息框。在构建阶段,您需要从另一个方案复制本地化 在UI测试目标->构建阶段->复制捆绑资源中,添加所需的本地化文件(例如Localizable.strings) 添加类似于以下内容的函数:
func localizedString(key:String) -> String {
/*1*/ let localizationBundle = NSBundle(path: NSBundle(forClass: /*2 UITestsClass*/.self).pathForResource(deviceLanguage, ofType: "lproj")!)
/*3*/ let result = NSLocalizedString(key, bundle:localizationBundle!, comment: "") //
return result
}
/*1 Gets correct bundle for the localization file, see here: http://stackoverflow.com/questions/33086266/cant-get-access-to-string-localizations-in-ui-test-xcode-7 */
/*2 Replace this with a class from your UI Tests
/*3 Gets the localized string from the bundle */
然后在代码中可以使用app.button[localizedString(“localized.string.key”)]
全文如下:Volodymyr的答案对我帮助很大,但如果本地化包文件夹名称与快照中设置的deviceLanguage不同,则可能会失败。这段代码在Swift 3.0和意大利语(当前语言环境为“it”,但设备语言为“it”)等语言中运行良好
我想实际测试UI功能的内容,而不仅仅是它们的存在,因此设置默认语言或使用可访问性标识符并不合适 这是基于和的答案。然而,他们的答案依赖于
deviceLanguage
,这需要在SnapshotHelper
中明确设置。此解决方案动态获取设备正在使用的实际支持的语言
可本地化的.strings
文件添加到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 "?"
}
localizedString(键)
localeCode
将是langCode scriptCode
(例如,zh Hans
)。否则,localeCode
将是langCode区域代码
(例如,pt BR
)。testBundle
首先尝试通过localeCode
解析lproj,然后返回到langCode
如果仍然无法获取捆绑包,它将返回“”作为字符串,因此它将使任何查找特定字符串的UI测试失败。除了Joe的答案之外,您还可以直接在测试代码中强制UI测试的语言,而无需编辑如下方案:
[tabBarsQuery.buttons["particiants"] tap];
- (void)setUp
{
[super setUp];
self.continueAfterFailure = NO;
XCUIApplication *app = [[XCUIApplication alloc] init];
app.launchArguments = @[@"-AppleLanguages", @"(en)", @"-AppleLocale", @"en_EN"];
[app launch];
}
SeanR的答案很好(+1),但有一个小小的改进: 如果使用基本本地化,则您的
可本地化.strings
可能无法在基本语言中本地化。这是不必要的,因为在这种情况下将使用基础语言。如果是这样,SeanR的函数localizedString
将返回.?
下面的扩展版本还会检查基础语言,并返回基础语言中的本地化字符串:
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 "?"
}
对于fastlane的快照功能,
SnapshotHelper.swift
使用这些参数启动应用程序。因此,通过解释这些值,此解决方案是确定性的,我能够为多种语言生成正确的快照:
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 ""
}
func-getLocale(str:String)->String{
let start=str.index(str.startIndex,offsetBy:1)
let end=str.index(开始,偏移量:2)
让range=start..String{
打印(“app.launchArguments\(app.launchArguments)”)
guard let localeArgIdx=app.launchArguments.index(of:“-AppleLocale”)else{
返回“”
}
如果localeArgIdx>=app.launchArguments.count{
返回“”
}
让str=app.launchArguments[localeArgIdx+1]
let locale=getLocale(str:str)
让testBundle=Bundle(用于:Snapshot.self)
如果让testBundlePath=testBundle.path(forResource:locale,类型为“lproj”)??testBundle.path(forResource:locale,类型为“lproj”),
让localizedBundle=Bundle(路径:testBundlePath)
{
返回NSLocalizedString(键,束:localizedBundle,注释:“”)
}
返回“”
}
class LocalizationHelper: NSObject {
class func localizedString(_ key: String) -> String {
let testBundle = Bundle(for: UITests.self)
let currentLocale = Locale.current
if let code = currentLocale.languageCode,
let testBundlePath = testBundle.path(forResource: code, ofType: "lproj") ?? testBundle.path(forResource: code, ofType: "lproj"), let localizedBundle = Bundle(path: testBundlePath) {
return NSLocalizedString(key, bundle: localizedBundle, comment: "")
}
return ""
}
}