View Controller TDD

Я пытаюсь добавить в свой проект несколько юнит-тестов для проверки контроллеров представления. Однако, похоже, у меня проблемы с, казалось бы, простыми вещами. Я создал пример проекта, на который я буду ссылаться.https: //github.com/pangers/ViewControllerTestin

Образец содержит UINavigationController в качестве начального контроллера представления. Корневым контроллером представления UINavigationController является FirstViewController. На FirstViewController есть кнопка, которая переключается на SecondViewController. В SecondViewController есть пустое текстовое поле.

Два теста, которые я пытаюсь добавить:
1) Проверьте заголовок кнопки в FirstViewController «Следующий экран».
2) Проверьте, что текстовое поле в SecondViewController пустое, "".

Я слышал сообщения о добавлении ваших быстрых файлов как к основной цели, так и к контрольной цели, что не является хорошей практикой. Но лучше сделать общедоступным все, что вы хотите, в своих тестах и импортировать основную цель в тесты. Вот что я сделал. (Я также установил «Определить модуль» для основной цели на YES, так как это то, что я прочитал в нескольких статьях

В FirstViewControllerTests я создал первый контроллер представления со следующим:

var viewController: FirstViewController!

override func setUp() {
    let storyboard = UIStoryboard(name: "Main", bundle: NSBundle(forClass: self.dynamicType))
    let navigationController = storyboard.instantiateInitialViewController() as UINavigationController
    viewController = navigationController.topViewController as FirstViewController
    viewController.viewDidLoad()
}

И я добавил тест:

func testCheckButtonHasTextNextScreen() {
    XCTAssertEqual(viewController.button.currentTitle!, "Next Screen", "Button should say Next Screen")
}

Аналогично, для SecondViewControllerTest я настроил его с помощью:

var secondViewController:SecondViewController!

override func setUp() {
    let storyboard = UIStoryboard(name: "Main", bundle: NSBundle(forClass: self.dynamicType))
    let navigationController = storyboard.instantiateInitialViewController() as UINavigationController
    let firstviewController = navigationController.topViewController as FirstViewController
    firstviewController.performSegueWithIdentifier("FirstToSecond", sender: nil)
    secondViewController = navigationController.topViewController as SecondViewController
    secondViewController.viewDidLoad()
}

И тест:

func testTextFieldIsBlank() {
    XCTAssertEqual(secondViewController.textField.text, "", "Nothing in textfield")
}

Они оба терпят неудачу, и я не уверен, почему. Я подозреваю, что способ, которым я создаю экземпляры контроллеров представления, не является правильным. Является ли лучший способ создания контроллеров представления, это использовать раскадровку (как если бы она работала в реальной жизни)? Или это приемлемо для реализации через:

var viewController = FirstViewController()

Какой у вас, ребята, опыт работы с TDD и быстрого просмотра контроллеров?

Я использую Swift с XCode 6.1.1.

Заранее спасибо

Решаемые

Хорошо, после рассмотрения ответов от modocache и Майка Таверна, я нашел свое решение и узнал несколько вещей, которые я напишу ниже.

1) Я сделал что-нибудь класс / метод / переменную, которую я хочу протестировать публично. Мне не нужно добавлять файлы swift к цели теста.

2) Мне нужно было только установить «Defines Module» для цели «Main» (в отличие от цели «Test» или всего проекта)

3) При создании сценария раскадровки следует установить значение nil, а не NSBundle (forClass: self.dynamicType), иначе тесты не пройдут.

4) Как было сказано в modocache, хорошо бы дать контроллеру представления StoryboardID и создать его экземпляры следующим образом:

viewController = storyboard.instantiateViewControllerWithIdentifier("FirstViewController") as FirstViewController

Однако создание такого экземпляра контроллера представления ТОЛЬКО создает экземпляр только контроллера представления, а не каких-либо контроллеров навигации, в которые он может быть встроен. Это означает, что попытка сделать

XCTAssertFalse(viewController.navigationController!.navigationBarHidden, "Bar should show by default")

приведет к нулевому исключению. Я подтвердил это с

XCTAssertNil(viewController.navigationController?, "navigation controller doesn't exist")

что привело к успешному тестированию.

Так как я хотел проверить состояние панели навигации в FirstViewController, вы должны создать экземпляр контроллера вида следующим образом:

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let navigationController = storyboard.instantiateInitialViewController() as UINavigationController
viewController = navigationController.topViewController as FirstViewController

Сейчас выполняю тест

XCTAssertFalse(viewController.navigationController!.navigationBarHidden, "nav bar should be showing by default")

результаты успешного теста.

5) let _ = viewController.view действительно вызывает viewDidLoad (), что было подтверждено тестом

6) let _ = viewController.view не вызывает viewWillAppear (), и я предполагаю, что что-нибудь потом тоже будет хорошо. viewController.viewWillAppear (false / true) необходимо вызвать вручную, чтобы вызвать его (подтверждено тестом).

Надеюсь, это поможет людям. Я отправлю обновленный проект на GitHub (ссылка выше), если кто-то захочет поиграть с ним.

Обновление # 2

После всего вышесказанного я все еще не мог понять, как перейти от первого контроллера представления ко второму контроллеру представления (чтобы я мог проверить свойства панели навигации в SecondViewControllerTests.swift). Я пыталс

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let nc = storyboard.instantiateInitialViewController() as UINavigationController
let firstVC = nc.topViewController as FirstViewController
firstVC.performSegueWithIdentifier("FirstToSecond", sender: nil)
secondVC = nc.topViewController as SecondViewController

который вызвал ошибку.

Я тоже пробовал

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let nc = storyboard.instantiateInitialViewController() as UINavigationController
let firstVC = nc.topViewController as FirstViewController
firstVC.toSecondVCButton.sendActionsForControlEvents(UIControlEvents.TouchUpInside)
secondVC = nc.topViewController as SecondViewController

который не сработал.

Я в конце концов попробовал

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let nc = storyboard.instantiateInitialViewController() as UINavigationController
vc = storyboard.instantiateViewControllerWithIdentifier("Second") as SecondViewController
nc.pushViewController(vc, animated: false)
let _ = vc.view
vc.viewWillAppear(false)

который отлично работал с моими тестами (позволил мне получить доступ к свойствам панели навигации)!

Ответы на вопрос(2)

Ваш ответ на вопрос