Testing network requests can be tricky. Generating mock data, handling HTTP routes, etc. Thing get complicated quickly. Today we'll check out a library from devlucky called Kakapo that can help us tame all this. Let's get started.
One of the best features of Kakapo is how easy it is start using. We can create a new Router for a domain, and start adding intercepted routes like this:
Code Coverage arrived with Xcode 7. It can help us visualize which parts of our code are not being tested enough (or at all). Let's dive in:
Before we can take advantage of Code Coverage, we'll need to enable it for our project. It's off by default.
We'll begin by editing our scheme, then selecting Test in the sidebar, then enabling the Gather coverage datacheckbox.
Now we'll run our tests by going to Product > Test in the menu (or pressing U). Then we can check out the test log where we'll find a new “Coverage” tab.
Xcode will display all the functions in our code with a bar graph indicating how well “covered” they are by our tests (We can mouse over to get an exact percentage). In our case, we are at 0%, since we don't have any tests. Yikes! Let's fix that by adding a simple test for a function on our PersonViewModel:
It's another fastlane friday here on LBOC. Today we'll be looking at another awesome tool in the fastlane suite called scan. It provides an easy way to run the tests of our iOS or OS X app. Let's dive in.
Before we begin, let's look at why a tool like scan can be helpful.
Xcode ships with a great command line tool called xcodebuild that allows to do all sorts of interesting things to our projects from the command line. It can be a bit verbose to configure though, and its output isn't very readable at a glance.
There's other tools like xcpretty that can help improve this output, but they take a fair amount of configuration as well.
That's where scan comes in. It takes care of all of this (plus a lot more) in one simple command: scan.
This is all we need for basics usage. scan will auto-detect things like our workspace, but we can always configure things as well:
scan --scheme "app-store"
Like other fastlane tools, we can run scan init to generate a new Scanfile, where we can store all our configuration options:
📃 Displays nice output, stores original xcodebuild log in ~/Library/Logs/scan
📄 Can generate HTML, JSON or JUnit reports
📣 Can send well-formatted test results to Slack. Check out the slack_only_on_failure configuration option to only report failed tests.
scan also helps with resolving common Xcode oddities like duplicated simulators or simulators that stop responding. Finally, scan works great with tools continuous integration tools like Jenkins and services like Travis. Happy testing!
Today we'll look at a couple more tips to get the most out of UI Testing in Xcode. (Covered previously in Bites #30, and #124).
Are We in a Test?
It'd be great if our app could know when it's running inside of a UI Test, then behave differently. We'll start by setting a flag that we can check for later. We'll add a launchArgument before we launch our app in our tests' setUpfunctions.
We can use this function throughout our code to do things like hit mock servers during testing, or simulate a camera preview when capturing screenshots with snapshot. (Bite #110).
Dismissing System Alerts
We have to jump through a couple of hoops here. First we'll need to set up what's called a "UI Interruption handler", which will execute a closure when the UI is interrupted by, for example, an alert being shown:
Then, after our app presents the authorization prompt, we'll need to .tap() on it once before the UI Interruption handler will fire. Inside our handler, we'll accept the prompt then return true to tell Xcode we've handled the UI interruption.
We covered the basics of UI Testing in Xcode when it was first announced all the way back in Bite #30. It's a fantastic way to test our app's interface. Today we'll look at a few more UI Testing odds and ends. Let's dive in:
First, let's write a test to verify that one of our table views properly loads and displays its data. The data is loaded asynchronously (which should be mocked in our test, but that's a future Bite). We'll need to give our app a little time to load and render the data we're testing for. We can use an expectation to easily pull this off: