When you write tests for your views, some will inevitably fail. This is the reason you are writing tests in the first place—to catch errors before users see the problems. In this video, learn about some of the common errors that you may encounter when testing your views with LayoutTest, and the ways to debug further or solve the issue. This is a great video to refer back to when using LayoutTest.
- [Narrator] When you're developing your test, you are likely to find that you may have made some mistakes in either your test or the layout of your view. In this and the following three videos, we'll look at some common errors you may find and how to diagnose and fix them. Let's open the Xcode Workspace for this video in 03_02. Now we're going to hit Cmd+u again to run all the tests, and we're going to see all the failures. Let's switch back to Xcode. In fact, let's take it out of fullscreen mode, so if we leave our mouse up top, once hit the green button, and just expand it like this so we don't get moved between spaces.
Okay, build succeeded, but test failed. Nine different errors. We're going to look at each failure, one at a time. It's always good to run all of the tests once, so that Xcode indexes the tests and allows you to run them more easily one at a time. Let's start by taking a look at the main storyboard. As you see, we have Main.storyboard, which is already open right now. We have one ViewController, and this ViewController looks like this. This illustrates that you can use Layout Test on any type of view, even if it's within a ViewController, which can be in an Interface Builder file or a .zib, or in a storyboard even.
Anything that has a UIView or inherits from UIView can be tested by Layout Test. Usually it makes more sense to make a Layout Test on small components, but in this case, the view only has standard UI Kit components, a backgroundImageView and a UI label. We can test the entire view. Let's go to the ViewControllerLayoutTests and see what's going on. We have nine failures, and we can look in the console to see what they are. Hit Cmd+Shift+y to show that area.
We can click and drag to expand. We could scroll through this console, or we can make it a little easier. If we go to the Report Navigator, which is here, we can twirl down this first one here and see the tests we ran today. Let's click this. Now we can click on the Logs tab to see all the different failures. Another view you can look at is the Issue Navigator. Both work, but you may find it a little easier to see more information in this view here.
As you can see, we have a bunch of errors. Let's take a look at one at a time. I click the More button on the first error to see all the detail, and we see it says "Failed - Bottom right corner of the ImageView," and then we have some ancillary information about that ImageView to help us identify it, and then it says "Overlaps upper left corner of UILabel." Again, more ancillary information about that label. "If this is intentional, you should add one of the views to ViewsAllowingOverlap." Because our ViewController has a backgroundImageView and a label on top of it, that means the UILabel is overlapping the backgroundImageView.
In this case, we do want that to happen, because it's a backgroundImageView. This message tells us how to fix that by adding one of the views to ViewsAllowingOverlap. Let's do this now. Let's go back to the Project Navigator, click on the ViewControllerLayoutTests. Let's hide the Console Window, Cmd+Shift+y, so we have more room. Now, views allowing overlap is an NSMutableSet, and any views you put in this will not error if something is overlapping it.
Let's add the code for this. In the runLayoutTests method, we're going to call viewsAllowingOverlap, as you see there's a property for that, .add, and we add the object. We want to add the ViewController's backgroundImageView, but if we just have the UIView itself, we don't have access to that property. That property is part of the ViewController, so we need access to the ViewController to be able to get that property.
How can we pass the information to this method runLayoutTests? Well, we have access to it in the view(forData) method because as you see here, we create a ViewController from the storyboard, and then we get its view and return that. This is where we can use this context. This context basically just holds a reference to any object. Let's add the ViewController as the context. To do so, we're going to simply type, "context." As you see this is an optional, so we're going to use optional chaining.
Question mark after context. .pointee = viewController. Now this context object points to the ViewController. For our purposes, we don't really need to worry too much about this being a AutoreleasingUnsafeMutablePointer. The point is it points to the ViewController. Sorry for all the pointing there. Now, in runLayoutTests, as this method passes us information, the context object will have the ViewController in it.
Now we need to get the ViewController in the runLayoutTests method. As I said, it's set to the context now. We could simply do something like this, "context," and cast it as the ViewController that we want. You could do something else with this, like use a guard statement and do an assert failure if there's some problem, or since it's a test, we can just use an As bang and move one. Now we need to add the backgroundImageView to the views that are overlapping.
We do ViewController.backgroundImageView. Great, that should fix this. Keep in mind that LayoutTests checks your entire view hierarchy for overlapping views, so even if you have a view that is a different custom view that you aren't even testing, if it's part of your view hierarchy, as in you added it as a sub view, your test will still fail if that custom view has overlapping views. Okay, now let's try running again. Cmd+u to run all the tests.
As we see, we've gone from nine errors to four. That's better. Let's keep going. Quick tip, instead of having to navigate to the logs every time, we can open it in a new tab, and it will stay that way. Let's hit Cmd+t to open a new tab, navigate to the logs, and now we're set here. Now we can go back to this tab when we want to actually edit the code.
- Installing the library
- Specifying test data
- Reviewing property-based testing
- Using test data and writing the LayoutTest test
- Testing views at different sizes
- Debugging with snapshots
- Dealing with common errors
- Advanced debugging tips
- Exploring catalog view