Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/94.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 带有本地化UI的Xcode 7 UI测试_Ios_Swift_Xcode7_Xcode Ui Testing - Fatal编程技术网

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目标
  • 将以下代码添加到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 ""
        }
    
    }