The idea of utilizing Test Driven Design when creating a project really excites me. To have a robust app from the beginning and working the design with the test in mind to assist with future refactoring ensuring the app remains working has become a must in the past few years.
With most mobile application complexity going beyond 3 different views (Master/Detail/Help), and the use of RESTful endpoints getting more complicated leads us to two avenues of thought, either test it manually often which consumes developer time, or implement some automated testing to save time and test often to ensure the application works properly.
In Test Driven Design (TDD) we want to test enough of the application, not just unit testing but UI as well so that we can ensure that all aspects of an application work properly. We can even do the things people do such as tap twice on a button to ensure a background task is only launched once and doesn’t bind/crash the app up.
Apple has done iOS developers a solid when they extended XCTest with XCUITest suite allowing us to automate UI testing. I still firmly believe there isn’t anything to fully do away with manual testing. Double and triple tapping buttons by frustrated users to lock apps up, for example, are one of those rare bugs that only show when the internet server is slowly responding to your request, or the device has slowed down after several iOS upgrades.
GitHub Project location: https://github.com/eSpecialized/WunderTDD
This isn’t a tutorial or learning blog post.
To use the source code and demonstrate the app, get a Developer API key from Wunderground here https://www.wunderground.com/weather/api/
Copy the key and paste it with Command+V into the simulator, and then click in the ApiKey under Config twice until you have a “Paste” option. Paste the key and click back.
Start time 3:00 PM 2018-01-23 Tuesday
The plan; Show weather information from an internet API which is JSON based. Show this information in a table list and a detail view. It appears I can include a weather map in the detail view.
This app is to demonstrate the following;
- Create a git repo for this named WunderTDD
- Create a project for the git with the same name
- Add a Configuration view so the Weather Unground API can be added (its a personal code with limits.) Then add that API key.
- I. XCTest for Unit test and create a Weather API swift module. WWunderAPI
- Utilizing RESTful JSON calls to an API endpoint using URLSessions and DataTasks
- Use the new Codable protocol in a struct to break down the JSON data using JSONDecode
- II. Increase the test quality by breaking apart the parts of the JSON Struct and verifying with a common location like Portland, OR, use XCAssert on parts of the structure for strings/doubles etc and ensure the data is populated and proper and the test passes
- III. Actually build the fetchWeather API out
- Displaying that information in a tableview
- Using XCUITest to update the tableview by adding a location, and checking that it really did so and the information that is available through the accessibility identifier in some cases, or the location by name for unique static texts.
After 1 hour 30 minutes, I have some scaffolding code inserted, I can insert and delete city objects using CoreData Events which have city, state, temperature, wind data in the objects. This helps facilitate persistence of data between runs.
At this point, I commence writing the first test. Which is to use the fetchWeather from WunderAPI by a unit test to ensure we get the proper data, and capture the stringed JSON value of output so I can then decode weather undergrounds data using codable in the Struct.
At 5:00 PM I am done with the first set of tasks. I took 15 a minute break, then back into the XCUITest portion of this WunderTDD App. I begin to dig back in at 5:15 PM
5:15 PM Next steps;
- Write the UI Test portions. The cells currently show a location, but I will need more info wind, temperature, and conditions.
- Add a UI Test for the add location functionality first, a new table cell should be added, and it should contain the city name of what is added. The added functionality uses the addUIInterruptionMonitor for intercepting the alert that shows, and you must tap the app anywhere to activate the monitor once the alert shows or it won’t activate.
- Find the new cell by the staticTexts[“Florence, OR”], waiting for its existence.
- Check for default cell text “…” in conditions for example. Test against this to ensure the conditions populates.
- Delete the newly added cell
by 6:38PM I have a tableview that looks like this;
At 7:24 PM I ended for the day on icon downloading. What I had grabbed from here didn’t work right with the weather icons; http://ioscake.com/how-to-load-gif-image-in-swift.html
Day 2 wrap up at 11:30 AM 2018-01-24
With the failure of that ioscake gif loader (it wants animated gifs and these aren’t animated) I will look to CocoaPods for a gif library. I was able to switch over to this gif CocoaPod https://github.com/kirualex/SwiftyGif and it worked out of the box to display gifs in the image view.
12:00 PM noon 2018-01-24
I’ve committed the entire CocoaPod with the project as I had to fix some files, the basic idea here is that someone who checks out the project should have everything to work with and you should get a working project on checkout.
- Edit the Detail view, with the developer plan I can show some limited information from Wunderground. I will display the radar/satellite map in detail animated.
- Write tests to confirm detail view shows up, proper title, the image radar view, and conditions.
- Refactor the first test to check for persistence of data between app launches. The first test will no longer delete the newly added location, and that code will become a third UI test to delete the added location.
- A support function is necessary to find the cell by its CityState location String.
by 1:30 PM I’m pleased with the results, the simple prototype is completed.
Time to write a Swift 4 iOS Prototype App with Test Driven Design;
4.5 hours day 1
2 hours day 2
6.5 hours grand total.
Features of this WunderTDD Prototype;
Allows adding a location by City, ST for some basic weather information.
The detail view shows the animated radar/satellite graphic.
Data persists between Application launches utilizing CoreData
Tests are written to ensure the application remains functional, with changes to UI or Model data will require updates to those tests.
All tests passing:
- Tests help solidify that functionality works as desired.
- Developers should have unit and UI tests of their apps to help increase the robustness of their application, which increases their confidence of delivery of quality applications to the customers.
- Developers (myself included) who used spreadsheets and manual testing in the past will appreciate the automated unit and UI Testing that XCTest brings, and the time saved per app updates will be amazing. It is all about efficiency and saving time for what is equally important; new Features!
- I find its easier to write tests in tandem for TDD. Write the test first, let it fail, update the module unit or ui and if needed update the test until all is passing.
- In an ideal world, we have all tests passing daily as part of a CI Continuous Integration Server that builds nightly. I won’t be covering that here.
A youtube video demonstrating the speed that Test Driven Design brings to testing both Unit and UI portions of applications.