View Controller TDD

Estoy tratando de agregar algunas pruebas unitarias a mi proyecto para probar los controladores de vista. Sin embargo, parece estar teniendo problemas con cosas aparentemente simples. He creado un proyecto de muestra al que me referiré. @https: //github.com/pangers/ViewControllerTestin

La muestra contiene un UINavigationController como el controlador de vista inicial. El controlador de vista raíz de UINavigationController es FirstViewController. Hay un botón en FirstViewController que pasa a SecondViewController. En SecondViewController hay un campo de texto vacío.

Las dos pruebas que intento agregar son:
1) El título del botón de verificación en FirstViewController es "Pantalla siguiente".
2) Verifique que el campo de texto en SecondViewController esté vacío, "".

He escuchado informes de agregar sus archivos rápidos tanto al objetivo principal como al objetivo de prueba no es una buena práctica. Pero más bien es mejor hacer público todo lo que quiera acceder en sus pruebas e importar el objetivo principal en las pruebas. Entonces eso es lo que he hecho. (También he establecido el "Módulo de definición" para el objetivo principal en SÍ, ya que eso es lo que también he leído en algunos artículos).

In FirstViewControllerTests He instanciado el primer controlador de vista con lo siguiente:

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()
}

Y he agregado la prueba:

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

e manera similar, para SecondViewControllerTest, lo configuré usando:

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()
}

Y la prueba:

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

Ambos fallan y no estoy muy seguro de por qué. Mi sospecha es que la forma en que estoy instanciando los controladores de vista no es correcta. ¿La mejor manera de crear instancias de los controladores de vista es usar el guión gráfico (como si se ejecutara en la vida real)? ¿O es aceptable ser instanciado a través de:

var viewController = FirstViewController()

¿Cuál es su experiencia con TDD y los controladores de vista en Swift?

Estoy usando Swift con XCode 6.1.1.

Gracias por adelantado

Resuelto

k, después de considerar las respuestas de modocache y Mike Taverne, encontré mi solución y aprendí algunas cosas que escribiré a continuación.

1) Hice cualquier cosa clase / método / variable que quiero probar pública. No necesito agregar los archivos rápidos al objetivo de prueba.

2) Solo necesitaba establecer "Define Module" para el objetivo "Principal" (en oposición al objetivo "Prueba" o el proyecto completo)

3) Al crear instancias del guión gráfico, el paquete debe establecerse en nulo en lugar de NSBundle (forClass: self.dynamicType), de lo contrario las pruebas fallarán.

4) Como dijo modocache, es bueno darle a su controlador de vista un StoryboardID e instanciarlos de esta manera:

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

Sin embargo, crear instancias del controlador de vista de esta manera SOLO crea una instancia del controlador de vista solo, y no de ningún controlador de navegación en el que pueda estar integrado. Eso significa, intentar hacer

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

resultará en una excepción nula. Confirmé esto con

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

que resultó en una prueba exitosa.

Dado que quería comprobar el estado de la barra de navegación en FirstViewController, debe crear una instancia del controlador de vista de la siguiente manera:

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

Ahora realizando la prueba

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

resultados en una prueba exitosa.

5) let _ = viewController.view realmente activa viewDidLoad () que fue confirmado por una prueba

6) let _ = viewController.view no desencadena viewWillAppear (), y supongo que cualquier cosa después también. viewController.viewWillAppear (falso / verdadero) debe llamarse manualmente para activarlo (confirmado por una prueba).

Esperamos que esto sea de ayuda para las personas. Enviaré el proyecto actualizado a GitHub (enlace de arriba) si alguien quiere jugar con él.

Update # 2

Después de todo lo anterior, todavía no podía entender cómo hacer la transición del primer controlador de vista al segundo controlador de vista (para poder probar las propiedades de la barra de navegación en SecondViewControllerTests.swift). Lo intent

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

que causó un error.

También probé

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

que no funcionó.

Finalmente intenté

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)

que funcionó perfectamente con mis pruebas (¡me permitió acceder a las propiedades de la barra de navegación)!

Respuestas a la pregunta(2)

Su respuesta a la pregunta