简体   繁体   English

如何单元测试`viewDidLoad()`

[英]How to unit test `viewDidLoad()`

What is everybody's favourite way of injecting dependencies when unit testing UIViewController.viewDidLoad() method on iOS?在 iOS 上对UIViewController.viewDidLoad()方法进行单元测试时,每个人最喜欢的注入依赖项的方式是什么?

Given my implementation is:鉴于我的实现是:

class MyViewController: UIViewController {

    var service: Service = Service()

    override func viewDidLoad() {
        super.viewDidLoad()
        service.load()
    }
}

And my test class is something along this:我的测试课是这样的:

class MyViewController Tests: XCTestCase {

     var vc: MyViewController!
     var serviceMock = ServiceMock()

    override func setUp() {
       super.setUp()
       let storyboard = UIStoryboard(name: "Main", bundle: nil)
       vc = storyboard.instantiateViewController(withIdentifier: "MyViewController") as! MyViewController
       vc.service = serviceMock
    }
}

func testThatServiceIsCalled() {

       XCTAssertTrue(serviceMock.loadCalled)
 }

The obvious problem here is that viewDidLoad() is called at the moment I instantiate the viewController and the test fails as the mock is not injected properly.这里明显的问题是viewDidLoad()在我实例化 viewController 时被调用,并且测试失败,因为模拟没有正确注入。

Any solution?有什么解决办法吗?

Why do you need to use the storyboard to create the view controller?为什么需要使用storyboard来创建视图控制器?

Wouldn't this work?这行不通?

func testThatServiceIsCalled() {
  let vc = MyViewController()
  vc.service = serviceMock
  vc.viewDidLoad()

  XCTAssertTrue(serviceMock.loadCalled)
}

TL;DR You should not unit test UI-related methods like this. TL;DR 你不应该像这样对 UI 相关的方法进行单元测试。

Controllers and Views are not suitable for unit testing for the simple reason that their usually involves operations that get reflected on the screen, and thus are (very) hard to test.控制器和视图不适合单元测试,原因很简单,它们通常涉及反映在屏幕上的操作,因此(非常)难以测试。 Snapshot testing or UI automation tests are a better candidate for these two components of MVC.快照测试或 UI 自动化测试是这两个 MVC 组件的更好候选者。

A well-written Controller doesn't contain business logic, it delegates the UI stuff to the View, and the business actions to its Model.编写良好的控制器不包含业务逻辑,它将 UI 内容委托给视图,并将业务操作委托给其模型。 With this in mind, it's the Model that should be the one that gets to be unit tested.考虑到这一点,模型应该是进行单元测试的模型。

Now, if you really want to assert that the your service get's called with the proper methods, you could set your VC as root view controller, this should ensure the loadView method gets called, which should trigger the viewDidLoad one:现在,如果你真的想断言你的服务被正确的方法调用,你可以将你的 VC 设置为根视图控制器,这应该确保loadView方法被调用,这应该触发viewDidLoad一个:

func testThatServiceIsCalled() {
    let window = UIWindow(frame:  UIScreen.main.bounds)
    window.makeKeyAndVisible()
    window.rootViewController = vc
    XCTAssertTrue(serviceMock.loadCalled)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM