【问题标题】:Unit Testing ViewController's Lifecycle单元测试 ViewController 生命周期
【发布时间】:2015-04-29 09:03:15
【问题描述】:

我正在为我的 ViewControllers 编写单元测试。 viewDidAppear:、viewWillAppear: 等方法的最佳实践是什么?

我正在使用调用 viewDidLoad 的 [vc view]。但是除了 viewDidLoad,我应该如何对其他生命周期方法进行单元测试。对它们进行单元测试是否很常见?直接打电话给他们有意义吗?喜欢:

[vc viewWillAppear:NO];
[vc viewDidAppear:NO];

谢谢

【问题讨论】:

  • 您具体要测试什么?在这种情况下,单元测试会提供什么价值?
  • 所以使用 UIView *v = [vc view] 我检查视图是否已加载而不是 nil,XCTAssertNotNil(v,@"Should be loaded")... 但对于其他生命周期方法,我如果有一个共同的单元测试实践,我正在尝试教育自己。我还打算增加代码覆盖率。
  • @ramo 我认为测试 UIKit 框架加载视图的能力没有太大价值,除非您担心无法在 .xib 或情节提要中建立正确的连接。

标签: ios objective-c unit-testing uiviewcontroller


【解决方案1】:

有很多开发人员要么避免要么不相信你可以测试 UIViewControllers。 Apples poor testing doco 对此也无济于事。

UIViewController 可以通过多种方法进行测试。

首先,正如任何人都会告诉你的那样,尝试将业务逻辑排除在视图控制器之外。试着让它只是加载视图,尽可能少地加载。从 MVC 架构更改为其他架构可能对此有所帮助。根据您正在构建的内容,您可能还需要考虑使用自定义 UIView 类来提供帮助。

纯单元/逻辑测试

您正在处理 Apple 所谓的“逻辑测试”,即没有分配可执行文件的测试目标。您仍然可以进行很多测试。包含简单视图处理代码的方法可以通过手动设置视图或使用测试代码手动加载 xib 文件等方式进行测试。OCMock 等模拟框架也非常有用。

通常,在这些类型的测试中,您最终需要手动执行各种生命周期方法来执行您想要测试的代码。例如,如果您想测试 viewDidLoad 方法:

id mockView = OCMClassMock([UIView class]);
// Setup mock expectations.
myViewController.view = mockView;
[myViewController viewDidLoad];

应用测试

如果您正在使用设置应用程序的测试目标,那么您实际上可以通过单元测试进行一些测试,而无需尝试导航应用程序。这有点作弊,但我发现它有时非常有用。

UIView *myView = // ... load the view manually or simply [[UIView alloc] initWithFrame:CGRectMake(0,0,100,100)]  
myViewController.view = myView;
[[UIApplication sharedApplication].keyWindow addSubview:myView];

如果您采用这种方法,请务必删除拆解中的视图。这样做的好处是,围绕在屏幕上获取视图的所有生命周期方法都会自动为您调用。

大多数情况下,我发现这对于测试与视图控制器和自定义视图相关的东西很有用,这些视图与属于大屏幕布局的一部分的视图相关。没有那么多顶级视图控制器。

界面测试

最后是 Apple 提供的新 UI 测试框架。我过去使用过诸如 Frank 和 Calabash 之类的第 3 方 Ruby 框架。事实证明,Apple 的 UI 测试实际上非常好,并且与这些工具相当。

它的诀窍是使用它来构建一个有意义的方法库,并帮助描述(使用 DSL)应用程序的各个方面。

这种方法的缺点是您不能只加载要测试的视图。您必须实际运行该应用程序并导航到它。另一个主要缺点是它非常基于应用程序的基于外部可访问性的视图。进入内部几乎是不可能的,因此测试是基于应用在屏幕上的行为而不是内部类。

到目前为止,我还没有探索过混合这种测试形式并手动将视图加载到窗口上的想法,但我不明白为什么这不起作用。

【讨论】:

  • 在混合 UI 测试和手动操作窗口的视图层次结构时 - 我认为这是不可能的,因为 UI 测试在应用程序的单独进程中运行,并且只能通过各种代理类访问提供用于检查 UI(如您所述,主要通过可访问性属性)。
  • 仍然无法进入viewDidLayoutSubviews::/
【解决方案2】:

您刚刚感受到 iOS ViewController 的一大弊端:它们的可测试性很差

MVC 的另一个大问题是它不鼓励开发人员 编写单元测试。由于视图控制器混合了视图操作逻辑 使用业务逻辑,将这些组件分离出来 单元测试成为一项艰巨的任务。许多人忽略的任务 赞成……只是不测试任何东西。

source

不要测试 UIKit!你应该测试你自己的逻辑。将逻辑放入您的 VC 中会使测试变得非常困难。尝试将其放在其他地方并单独对其进行单元测试。答案是:你应该避免通过调用 UIKit 方法进行测试——尤其是这些方法不是设计用来直接调用的!

如果你把所有的逻辑都从 ViewController 中提取出来,它就会真正变成一个视图:一个在屏幕上显示某些东西的哑类。那里应该没有什么要测试的。

也许您应该考虑改用 MVVM/MVP/VIPER。请阅读提供的链接,它将解释一切。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-21
    • 1970-01-01
    • 2015-02-06
    • 2020-09-06
    相关资源
    最近更新 更多