Group Group Group Group Group Group Group Group Group

raywenderlich.com Forums

iOS Unit Testing and UI Testing Tutorial

Learn how to add unit tests and UI tests to your iOS apps, and how you can check on your code coverage.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/709-ios-unit-testing-and-ui-testing-tutorial
1 Like

Writing tests isn’t glamorous

It isn’t!? I love writing tests. :wink:

I’ll bet you’re in high demand! and yes, I really enjoyed writing this article :]

Addendum: Often, you need to make some changes to the app code in order to write tests. I didn’t do this in the article — I think I pre-tweaked my apps so it wouldn’t be necessary — but I think Xcode is a bit more stable if you do the tweaks before you import the app into the test bundle. Otherwise, you might have to restart Xcode/your Mac multiple times, before it stops saying it can’t find your app!

Hey Audrey,
awesome guide, thank you very much!

While looking into how to apply this to my app, a couple of questions came to my mind. One of them is the following:

I wanted to start with adding tests to the requests I send with AFNetworking to our backend. The natural start would be testing authentication for login, logout and the such. The issue is that I save the token in a singleton after authentication is successful and don’t necessarily return it as part of the login method. Since testing async network calls, testing the logout call before login has finished is not a given (both login and logout work with the singleton that holds the user authentication status).

Is there a general best practice for testing user authentication? Should I update the input and output params of my methods?

Thanks again! :] This’ll get me started into the world of testing.

hi Björn: I’m not a testing expert, but the testing wizards I know seem to exert a lot of effort refactoring code to make it easier to test, and adding parameters to methods ranks high on the list: to expose hidden dependencies, so making it easier to inject dependencies. The Michael Feathers book I link to at the end of the tutorial is a valuable resource for learning new ways to think about designing code to be testable.

Is your authentication OpenID Connect/OAuth2? I adapted some Stormpath code for my upcoming URLSession video course, and stored the tokens in keychain, using KeychainWrapper.

I’m not sure what you mean by “not a given”: if you need a way to ensure login has finished before you try to logout, you might try wrapping them as asynchronous Operations, and setting a dependency. This is covered in our Concurrency video course.

@audrey Great article! Testing is rarer than it should be for mobile development. I think the biggest reason is the massive view controller problem. Hopefully, movement towards function programming, value-oriented programing and unidirectional data flow will help as it makes code more compose-able and testable.

https://www.raywenderlich.com/114456/introduction-functional-programming-swift


In terms of next steps, how about a tutorial using buddy build as a CI with automated testing? They have a free tier which could be helpful for those focused on learning.

  • As a side note, I used to work at SVL, too. I was there from 2003-2006.

Nice explanation but I still find UI testing very cumbersome.

UI testing looks easy when demonstrated with such simple examples like testing for existence of UI elements. But it becomes very difficult when you have to check for the contents of these elements .
Let’s say I want to check whether correct image is displayed in the image view.
I tried using the query selector in xcode but it’s confusing . Sometimes you just cannot access the image view or it’s properties.
So how can we achieve something like this ? Is there any simple way to know what kind of queries we can use on UI elements ?

yes, there are many blog posts expressing disappointment with UI Testing; hopefully Apple is working to improve it, and their documentation.

https://blog.metova.com/guide-xcode-ui-test/ looks like a good resource. It summarises a lot from Joe Masilotti’s articles/github, much of which has been taken down, at Apple’s request. But the metova article links to their own forked copy.

Masilotti’s http://masilotti.com/ui-testing-cheat-sheet/ is still up, and looks really useful, although the last reply from Masilotti was 10 months ago.

Agree about the MVC problem!

And CI/CD is on the wishlist, but it would be about Xcode Server. I know Ray accepts commissions from companies, like his current screencasts on Perfect, so if you know anyone at buddy build …

@audrey I know some people at buddy build. Can you DM me about commissions?

wait, that wasn’t a reply to you, Joe

paging @raywenderlich

or contact Ray directly?

Thanks @audrey ,very helpful !

you’re very welcome!

Hi Audrey,

Thanks very much for the article. It clears a lot of things up on a project I just inherited. However, I am stuck on one spot in this tutorial. You say:

Open the little menu next to [“Slide”] and select segmentedControls.buttons[“Slide”]

I am using Xcode 8.2.1 and cannot find this “little menu” anywhere. Could you take a quick screen shot of where this is so I can continue?

Thanks
kt

hi kt: it appears when you record:

Stop recording; it should still be there. It can be a little tricky getting it to open its menu:

btw Joshua Greene has updated the Testing video course, and goes into more detail about unit and UI testing.

Hi A,

Thanks so much for responding, on a Sunday no less. I got it, your explanation was great. One of the problems was that I was tapping on the “slide” itself, at the top, not the Slide/Type switch at the bottom right. This was giving me a different outcome and hence, no menu to choose. Once I actually tapped on the right thing, the menu came up like you said.

Much appreciated.
kt

Hi, Audrey!
Great post, thank you!
Why do you use:

controllerUnderTest = UIStoryboard(name: "Main", 
      bundle: nil).instantiateInitialViewController() as! SearchViewController!

to create instance instead of just:
controllerUnderTest = SearchViewController()

This instantiates the view controller from the storyboard, ensuring that all its outlets are also instantiated. I think it’s not really necessary in this particular case (testing that response is parsed correctly), but it’s a good habit to get into, in case your test checks the state of the view controller’s outlets.

In this case, too, the SUT is the view controller only because the networking code is embedded in the view controller, instead of separated into its own module.

Thank you for explanation!