Time to write another test!

We want to use our new CustomView in a UIViewController and luckily we have one.

Go to the test navigator and right click to create a new unit test class

I like making them this way, it’s a personal preference thing.

Call your new class ViewControllerTests delete the boilerplate and import your project. You must have this line at the beginning of ViewControllerTests.swift or your tests won’t work.

@testable import TestingNibs

Still in ViewControllerTests.swift , below the class definition, write your first test.

func testViewControllerHasCustomView() {

guard let vc = UIStoryboard(name: "Main", bundle: nil)

.instantiateInitialViewController() as? ViewController

else {

XCTFail("Could not instantiate vc from Main storyboard")

return

}

}

First step, make sure we can get the vc from the storyboard.

Run your tests again!

watch it pass, ignore the compiler warning about the unused variable, you’ll use it soon.

Now add the rest of the code so your test looks like this:

func testViewControllerHasCustomView() {

guard let vc = UIStoryboard(name: "Main", bundle: nil)

.instantiateInitialViewController() as? ViewController

else {

XCTFail("Could not instantiate vc from Main storyboard")

return

} vc.loadViewIfNeeded()



guard let customView = vc.customView else {

XCTFail("ViewController should have outlet set for customView")

return

}

let size = CGSize(width: 200, height: 200)

XCTAssertEqual(customView.frame.size, size,

"customView on ViewController should be correct size")

}

Notice we added vc.loadViewIfNeeded() this triggers the lifecycle methods your class needs to load views from the storyboard.

Then we added a guard clause to make sure we have an outlet set, and an assertion about the size of the frame we want the view to appear in. The size of the frame doesn’t matter, the point is that you can test almost everything you do in code or on a storyboard.

Run your tests again!

Watch it fail.

Value of type ‘ViewController’ has no member ‘customView’

Make it green! (again)

The first thing to do is get this to compile.

Add an outlet in code to ViewController

@IBOutlet weak var customView: CustomView!

Run your tests again — wait, what?!?!

You’re probably thinking — “I know this will fail because my outlet isn’t hooked up, why would I run a test that I know will fail?”

Tangent Time. This is a best practices thing. Make the smallest change you can to get over the hurdle that’s blocking you. I’d elaborate but Sandi Metz has a much better explanation in her book 99 Bottles of OOP, she referes to this type of intentionally kludgy problem solving as “Shameless Green”.

Shameless Green is defined as the solution that quickly reaches green while prioritizing understandability over changeability. It uses tests to drive comprehension, and patiently accumulates concrete examples while awaiting insight into underlying abstractions… …although Shameless Green is neither clever nor changeable, it is the best initial solution to many problems… Sandi Metz, 99 Bottles of OOP

I linked the sample but if you’re interested in TDD buy her book. It’s really good.

This solution of writing the outlet and running the tests before hooking it up follows the Shameless Green principle, it’s the cheapest solution to get over the error that you’re seeing. So…

Run your tests again!

and watch it fail again, of course.

ViewController should have an outlet set for customView

Make it green! (again)

Open Main.storyboard and add a new view to ViewController

Give it constraints for center and vertical position and set the class of the new view to CustomView

Ignore the constraint errors, I’m trying to make a point here

Next, hook up the outlet from Main.storyboard .

Finally you can hook up the outlet your defined in ViewController.swift .

Run your tests again!

Kaboom! It fails with the error, “(“(240.0, 128.0)”) is not equal to (“(200.0, 200.0)”) — customView on ViewController should be correct size”

You could have set height and width constraints when you set the vertical and horizontal constraints but instead you made the smallest possible change to get over the error you were seeing. This seems like a waste of time and for something like this it probably is, but the practice is important. You reap the benefits of TDD on more complex problems in more complex code bases. Establishing good habits is important.

(“(240.0, 128.0)”) is not equal to (“(200.0, 200.0)”) — customView on ViewController should be correct size

Make it green! (again)

add height and width constraints of 200

Run your tests again!

Green! Hooray!