Тестирование UITableView в UIViewController программно создается - PullRequest
0 голосов
/ 14 июня 2019

Я хочу внедрить свой диспетчер данных в мой контроллер представления и проверить его.

ViewController:

class ViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!

    var alert: AlertViewController?

    var coreDataManager: CoreDataManagerProtocol?

    init(coreDataManager: CoreDataManagerProtocol) {
        self.coreDataManager = coreDataManager
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.coreDataManager = CoreDataManager()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")

    }

    @IBAction func addItem(_ sender: Any) {
        alert = UIStoryboard(name: Constants.alertStoryBoard, bundle: nil).instantiateViewController(withIdentifier: Constants.alerts.mainAlert) as? AlertViewController
        alert?.title = "Enter your task"
        alert?.presentToWindow()
        alert?.delegate = self
    }
}

extension ViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return coreDataManager?.getTasks().count ?? 0
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let data = coreDataManager?.getTasks()[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        cell.textLabel?.text = data?.value(forKey: Constants.entityNameAttribute) as? String
        return cell
    }
}

Я хочу проверить это путем введения в mock в контроллер представления:

class CoreDataManagerMock: CoreDataManagerProtocol {
    var storeCordinator: NSPersistentStoreCoordinator!
    var managedObjectContext: NSManagedObjectContext!
    var managedObjectModel: NSManagedObjectModel!
    var store: NSPersistentStore!

    func getTasks() -> [NSManagedObject] {
        managedObjectModel = NSManagedObjectModel.mergedModel(from: nil)
        storeCordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)

        do {
            store = try storeCordinator.addPersistentStore(
                ofType: NSInMemoryStoreType, configurationName: nil, at: nil, options: nil)
        } catch {
            // catch failure here
        }
        managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
        managedObjectContext.persistentStoreCoordinator = storeCordinator

        var localTasks = [NSManagedObject]()
        let entityOne = NSEntityDescription.insertNewObject(forEntityName: Constants.entityName, into: managedObjectContext)
        entityOne.setValue(false, forKey: Constants.entityCompletedattribute)
        entityOne.setValue("Enter your task", forKey: Constants.entityNameAttribute)
        localTasks.append(entityOne)
        return localTasks
    }

    func save(task: String) {
        //
    }

}

Но я изо всех сил пытаюсь это проверить.

Я не могу запросить ячейку, поскольку я не создаю экземпляры из Storyboard (и я не могу, так как мне нужновнедрить фиктивный главный менеджер

Но так как tableView равен nil, то nil, поэтому я не могу зарегистрировать ячейку. Как я могу проверить cellForRow (в: когда я внедряю свою зависимость, как указано выше?

1 Ответ

0 голосов
/ 14 июня 2019

Как я проводил тестирование с UIStoryboard экземплярами UIViewController s, так и делал.

// STEP 1
// instantiate the storyboard
let storyboard = UIStoryboard(name: "SomeStoryboard", bundle: nil)

// STEP 2
// instantiate the UIViewController using the storyboard
let sampleViewController = storyboard.instantiateViewController(withIdentifier: "SampleViewController") as! SampleViewController

// STEP 3
// set the properties you need to set 
sampleViewController.xxxxx = "foo"
sampleViewController.yyyyy = "bar"

// STEP 4
// call the view so the ui objects would be instantiated
// not doing this would cause a crash
// this also calls `viewDidLoad()`
_ = sampleViewController.view

Так что в вашем случае, как выглядит код:

func testtv() {
    let storyboard = UIStoryboard(name: "INSERT STORYBOARD NAME HERE", bundle: nil)
    let viewController = storyboard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
    viewController.coreDataManager = CoreDataManagerMock()
    _ = viewController.view

    // I'm not sure about the code below this comment
    // but the above code should work

    viewController.tableView(UITableViewMock(), cellForRowAt: IndexPath(row: 0, section: 0))

    let actualCell = viewController.tableView?.cellForRow(at: IndexPath(row: 0, section: 0) )

    let test = viewController.tableView(UITableViewMock(), cellForRowAt: IndexPath(row: 0, section: 0))
    XCTAssertEqual(actualCell?.textLabel?.text, actualCell?.textLabel?.text)
}

ViewController

Почему это так, потому что вызов instantiateViewController(withIdentifier: _) использует init?(coder aDecoder: NSCoder)

Вы можете удалить этот фрагмент ниже, потому что он вам не нужен, и он не будет работать, так какUIViewController, который вы создаете, взят из раскадровки.

init(coreDataManager: CoreDataManagerProtocol) {
    self.coreDataManager = coreDataManager
    super.init(nibName: nil, bundle: nil)
}

Вместо этого вы можете создать статический метод для создания экземпляра UIViewController с нужными вам параметрами.Пример:

class SomeViewController: UIViewController {
    var someObject: SomeObject!

    static func instantiate(someObject: SomeObject) -> SomeViewController {
        let storyboard = UIStoryboard(name: "SomeStoryboard", bundle: nil)
        let viewController = storyboard.instantiateViewController(withIdentifier: "SomeViewController")
        viewController.someObject = someObject
        return viewController
    }
}

// usage
let vc = SomeViewController.instantiate(someObject: SomeObject())
// or
let vc: SomeViewController = .instantiate(someObject: SomeObject())
...