MixboxBuiltinDi 0.3.46

MixboxBuiltinDi 0.3.46

Artyom RazinovArtyom RazinovVladislav AlekseevTimofey SoloninAlexey Shpirko 维护。



  • 作者
  • Avito 代码蜂巢

概览

Version License Build Status

Mixbox 是一款功能强大的iOS端端到端UI测试框架。

目前它在Avito得到应用,我们拥有超过700个E2E UI测试用例,其中大约90%通过了测试,帮助我们在两年内减少了人工测试的工作量。大约25%在PR上执行,我们正在努力使100%的测试在PR上执行,部分是通过从黑盒E2E测试切换到灰盒测试来实现的。我们同时在三个平台上运行这些测试,总共大约需要40分钟(测试总时长为30+小时),因为我们使用了Emcee,一个可以在多台机器上运行测试的测试执行器(注意:Mixbox 不需要Emcee)。我们也在编写灰盒测试(其中包含对类、网络等一切内容的模拟),但我们刚刚开始。

如果您对在公司中使用它感到充满热情,请向我们提交一个问题。我们正在努力使其对社区可用,但这并不是我们的主要目标。

特性

  • 动作和检查(明显)

  • 像素级可见性检查

  • 一切都有轮询

  • 完全自动的滚动

  • 黑盒和灰盒测试!

    • 黑盒测试在单独的应用中运行,并能够启动应用。您可以使用这种类型的测试来测试更多应用功能。您可以使用模拟,但这需要您编写更多代码(使用启动参数或实现进程间通信)。
    • 灰盒测试在应用程序内部运行(如EarlGrey所示),但测试与黑盒测试兼容,因此您可以共享测试模型、页面对象、测试助手等。由于测试在同一进程中执行,可以轻松模拟任何事物。不使用模拟测试启动应用程序是不可能的。

    大部分代码在灰盒测试和黑盒测试之间共享,就像大部分功能一样。两种方法都有自己的优点。使用这两种方法可以达到良好的测试金字塔效果。

  • 页面对象

    • 内部可以包含任何代码
    • 页面对象元素可以嵌套元素(然而,这需要一些不太美观的模板)
    • 所有内容(动作/检查)都是可扩展的。如果您实现了自定义动作或检查,它将自动适用于黑盒和灰盒测试(参见SwipeAction,所有内置动作实际上都是扩展)。
  • UICollectionView中的每个单元格在测试中都可见(包括屏幕外的单元格)

  • 可配置应用程序与测试之间的进程间通信

  • 为在测试中可见的视图设置自定义值

  • 网络模拟(通过NSURLSessionProtocol)

  • 设置权限(相机/地理位置/通知等)

  • 推送通知的模拟(限制:仅限于活动应用程序内部!)

  • 从测试中打开URL

  • 地理位置的模拟

  • 硬件键盘(定义的键码很少,但它可以很容易地实现)

  • 无需分叉存储库即可自定义

  • Swift & Objective-C

  • 经过测试

    • 在3种设备配置上执行了176项黑盒UI测试
    • 在3种设备配置上执行了155项灰盒UI测试
    • 在4种设备配置上执行了100项单元测试
    • SwiftLint +自定义linter
    • 每次将请求到Mixbox时都会执行所有测试,通常1个PR等于1次提交。
    • 两个示例使用五个版本的Xcode进行了测试(10.0、10.1、10.2.1、10.3、11.0)。
  • 可配置报告(例如:Tests项目已集成到Allure,一个具有Web UI的开源报告系统,在Avito中我们使用内部解决方案来生成报告;您可以编写自己的实现)

开发中/尚未开源

  • 页面对象的代码生成
  • 获取所有应用程序中的断言失败
  • 处理弹簧板的门面
  • 在发布版本和测试构建之间切换可访问性值

安装

Mixbox有两种使用方法。

第一种描述在演示中,它过于简化,基本上您只需使用pod SomePod

第二种我们在Avito中使用,如下所示:测试(在那里查看Podfile)。

目前文档还不够,因此您可以尝试简单地将Mixbox链接到(演示),但请使用测试中的代码示例。

支持的 iOS/Xcode/Swift 版本

  • Xcode 11
  • Swift 5
  • iOS 10.3、iOS 11.4、iOS 12.1,中间版本可能工作或不工作,提到的版本已在 CI 上测试
  • Cocoapods 1.8.4
  • Mac OS 10.14.6

Xcode 9/10 及更早版本不再支持。如果您计划在不同的环境中使用项目并出现问题,请告诉我们。

已知问题

  • 在 iOS 11.2 上崩溃(在 iOS 11.3、iOS 11.4 上运行良好)
  • 在物理设备上设置权限不起作用(可能还有其他,我们在物理设备上没有测试;基本功能正常工作)
  • 未测试设备旋转,我认为我们在这方面有错误
  • 未测试 iPad
  • 报告中的俄语(将很快修复)

示例

关于实际示例,请参阅 Tests 项目。它是如何使用它的最新开源示例,但它缺乏现实性(没有展示如何为一个真正应用编写测试)。

显示基本功能的测试示例

func test() {
    // Setting permissions
    permissions.camera.set(.allowed)
    permissions.photos.set(.notDetermined)

    // Functions are useful in page objects and allows
    // reusing code, for example, for transitions between states of the app
    pageObjects.initial
        .authorize(user: testUser)
        .goToCvScreen()
        
    // Aliases for simple assertions (you can add your own):
    pageObjects.simpleCv.view.assertIsDisplayed()
    pageObjects.simpleCv.title.assertHasText("My CV")
    
    // Fully customizable assertions
    pageObjects.simpleCv.addressField.assertMatches { element in
        element.text != addressFieldInitialText && element.text.isNotEmpty
    }
    
    // Network stubbing.
    networking.stubbing
        .stub(urlPattern: ".*?example.com/api/cv")
        .thenReturn(file: "cv.json")
    // There is also a monitoring feature, including recording+replaying feature that
    // allows to record all network and replay in later, so your tests will not require internet.
    
    // Actions
    pageObjects.simpleCV.occupationField.setText("iOS developer")
    pageObjects.simpleCV.createCVButton.tap()
}

声明页面对象

public final class MapScreen:
    BasePageObjectWithDefaultInitializer,
    ScreenWithNavigationBar // protocol extensions are very useful for sharing code
{
    // Basic locator  
    public var mapView: ViewElement {
        return element("Map view") { element in
            element.id == "GoogleMapView"
        }
    }
    
    // You can use complex checks
    // Note that you can create your own matchers like `element.isFooBar()`
    public func pin(coordinates: Coordinates, deltaInMeters: Double = 10) -> ViewElement {
        return element("Pin with coordinates \(coordinates)") { element in
            element.id == "pin" && element
                .customValues["coordinates", Coordinates.self]
                .isClose(to: coordinates, deltaInMeters: deltaInMeters)
        }
    }
}

声明自定义页面对象元素

public final class RatingStarsElement:
    BaseElementWithDefaultInitializer,
    ElementWithUi
{
    public func assertRatingEqualsTo(
        _ number: Int,
        file: StaticString = #file,
        line: UInt = #line)
    {
        assertMatches(file: file, line: line) { element in
            element.customValues["rating"] == number
        }
    }
}

粘贴的代码

该库包括从其他库粘贴的一些代码。有时它是一个单独的文件,有时是因为我们需要在源代码中内置条件编译,以防止释放构建中链接代码。

  • EarlGrey(每个使用EarlGrey的源文件都包含EarlGrey子串)。[在这里可以找到许可证(Apache)](Docs/EarlGreyLicense/LICENSE)。它是可见性检查器,设置可访问性等。原始仓库:https://github.com/google/EarlGrey
  • AnyCodable。增加了#if语句。原始仓库:https://github.com/Flight-School/AnyCodable
  • SBTUITestTunnel。当版本超过3.0.6的网页视图出现一个错误。然后在几年后,我们在构建它时遇到了不一致的问题。修复方法非常原始——直接复制粘贴以避免问题。我们可以深入研究,但我们计划未来使用原生的IPC解决方案,所以没有这么做。原始仓库:https://github.com/Subito-it/SBTUITestTunnel
  • CocoaImageHashing。我们需要一个兼容性问题的修复,不能合并,([

用于测试中

其他文档