iOS Unit Testing - Its about TDD, unit testing, and creating bug free code on iOS.

Web Name: iOS Unit Testing - Its about TDD, unit testing, and creating bug free code on iOS.

WebSite: http://iosunittesting.com

ID:248992

Keywords:

about,TDD,unit,Its,iOS,Unit,Testing,free,

Description:

keywords:
description:It's about TDD, unit testing, and creating bug free code on iOS.
@Testable keyword in Xcode 7 Swift, XCTestRon

I wont duplicate what Natasha the Robot posted about @Testable in Swift 2. Its short and sweet. Check it out.

Thank you, Natasha!

Leave a comment
Tests help catch simple mistakes Swift, XCTestRon

This morning I ran into yet another example of where tests can help you catch simple mistakes. Im working on creating a custom control that simulates an automotive style fuel gauge.

This involves rotating a needle layer to indicate the fuel level. However, I dont want to needle to rotate across the bottom 1/4th of the circle (over the gas pump icons), only across the top 3/4ths.

This became a problem when I added animations. UIView.animateWithDuration always takes the shortest distance. So animating the needle from pointing to empty to having it point to full would result in the needle moving counter-clockwise across the bottom of the gauge. A real gauge would never do that.

So to fix this problem, I split the animation into 2 sections. When the distance to move the needle is equal-to-or-greater than 180 degrees, then I use 2 animations, each of which are less than 180 degrees. So I created a method to perform the 180 degree test as shown:

func angleInRadiansIsEqualToOrGreaterThan180Degrees(angle: CGFloat) - Bool {
let isGreaterThan180degrees: Bool = angle = CGFloat(M_PI_2) || angle = CGFloat(-M_PI_2)
return isGreaterThan180degrees
}

Unfortunately, angles are expressed in radians, not degrees, and thats where I made the mistake. My quick, mental conversion of degrees-to-radians was wrong; 180 degrees equals pi, not pi/2. This mistake didnt cause the code to fail, it just didnt work as desired (using 2-part animations for all angles greater than 90 degrees instead of 180).

This morning I was going back and adding unit tests to the code (blush: not using TDD since this is a spike to figure out how to do the animations). In doing so, I correctly calculated the number of radians, causing the new tests to fail:


func testAngleInRadiansIsEqualToOrGreaterThan180DegreesTrueFor180() {
let angle = convertDegreesToRadians(180)
XCTAssertTrue(fuelGaugeView.angleInRadiansIsEqualToOrGreaterThan180Degrees(CGFloat(angle)), "Angle is equal to 180, but reported false")
}

func testAngleInRadiansIsEqualToOrGreaterThan180DegreesFalseFor90() {
let angle = convertDegreesToRadians(97)
XCTAssertFalse(fuelGaugeView.angleInRadiansIsEqualToOrGreaterThan180Degrees(CGFloat(angle)), Angle (97) is less than 180, but reported true)
}

func convertDegreesToRadians(degrees: Float) - Float {
let radians = Float(M_PI / 180) * degrees
return radians
}

This raises a couple interesting points:

Beware of mental math; for example, converting degrees to radians in my head in this case. I was lucky, and the 2nd time got it right, so my tests exposed the problem. However, I could very easily have made the exact same mistake in my tests.Where possible, use explicit calculations in your tests (if not also in your code). In this example, I created a convertDegreesToRadians() method in my tests. Had there been a similar function available in math.h, I would have used it.

Note: I will be releasing this code to GitHub shortly. It will include all of the code for a framework containing a set of animated, automotive style gauges including Fuel gauge, Speedometer, and Tachometer. Ill update this post with a link once it is available.

One comment so far
Using Overridable Properties Instead of Tell Dont Ask SwiftRon

In order for objects to be easily testable, it is often good practice to use Tell, dont ask. What this phrase means is that methods should not directly ask for (create) system objects that they need. Instead, they should be told which system object to use.

This really runs contrary to common iOS practice though. It is very common, even in Apple example code, to see objects creating system objects whenever and wherever needed.

For example, a class needing access to CoreLocations CLLocationManager object will typically insert the following statement wherever it is needed:

let locationManager = LocationManager()

This is quick and easy, but makes testing difficult. Unit test would probably want to ensure that calls to locationManager occur, either by testing for side effects, or else using a test double (mock) in place of a real LocationManager instance.

Tell, Dont Ask would suggest that the class or method needing an instance of LocationManager be passed that instance. A negative effect of doing this though, is that the creator of the object or caller of the method needs to know about, and/or create the other object to pass. In this case, it would need to import CoreLocation.

// Create beacon class and determine if we're near it// caller code passes instance of CLLocationManager to init let myBeacon = MyBeaconClass(locationManager: CLLocationManager()) let isNear = myBeacon.isNear()// or passes it to specific methods that need it let myBeacon = MyBeaconClass() let isNear = myBeacon.isNear(locationManager:CLLocationManager())

Recently I have been working on cleaning up a reusable beacon class. I am trying to encapsulate it to the point that a user of the class would not need to know anything about CoreLocation. However, in the above example, the user would need to create an instance of LocationManager() to pass to the classs initializer or to individual methods.

After pondering this a bit, I believe that in this case it works better to have locationManager defined as an instance variable (var instead of let) that is initialized by the beacon class initializers, but can then be overridden by the unit tests. This allows the unit tests to replace the default instance of LocationManager with a mock object, but does require the product code user to know anything about CLLocationManager. So this code would look like this:

// Create beacon class and determine if we're near it  let myBeacon = MyBeaconClass()  let isNear = myBeacon.isNear()

It is perfectly ok for the unit tests to have to know about CoreLocation, so the test code would look something like this:

  // Create beacon class and determine if we're near it.  let beaconUnderTest = MyBeaconClass()  // Substitute a mock object  beaconUnderTest.locationManager = MyMockLocationManager()  let isNear = beaconUnderTest.isNear()

One big consideration when doing this is to keep the amount of work being done in the initializer small. If the instance of LocationManager is being manipulated during initialization, this manipulation may be difficult to test. So it may be necessary to provide separate methods to be called after initialization. The Single Responsibility Principle probably suggests doing this anyways.

Tell, Dont Ask is still a recommended best practice. But it appears that in some cases using overridable instance variables provides better separation of concerns.

View all 2 comments
Swift Test Coverage Code Coverage, Swift, Xcode 6Ron

Currently code coverage reporting for Swift code is broken. There is a radar open for this: rdr://15121260
This bug is preventing .gcov records from being generated.

If you are wanting to track test code coverage for your Swift code, please dup rdr://15121260 to help Apple assess the number of developers impacted by this issue.

Leave a comment
Testing Swift Protocol Delegates Swift, Xcode 6, XCTestRon

I ran into an interesting problem when trying to test that a delegate was set. Heres a simplified example:

protocol MyProtocol {  func myMethod()}class ClassWithDelegate {  var delegate: MyProtocol?  ...}class ClassUnderTest: MyProtocol {  var otherClass: ClassWithDelegate  init() {    self.otherClass = ClassWithDelegate()    self.otherClass.delegate = self  }}

In order to test that our ClassUnderTest is instantiating the ClassWithDelegate and setting its delegate, we could do the following:

class OurTests: XCTestCase {  var testClass: ClassUnderTest()  ...  func testThatOtherClassCreated {    XCTAssertNotNil(testClass.otherClass)  }  func testThatOtherClassDelegateSet {    XCTAssertTrue(testClass.otherClass.delegate === testClass)  }}

This looks pretty simple, right? For those of us still learning Swift, it isnt simple. What happens is that the compiler refuses to build, with the error: MyProtocol is not identical to AnyObject.

After tons of reading, and learning a lot about Swift protocols and pointers, I basically stumbled upon the solution: add the class keyword to the protocol. This tells the compiler that only objects will implement the protocol, not structs. It then is quite happy to perform tests for nil and/or identicalness (?). So the working protocol definition looks like this:

protocol MyProtocol : class {  func myMethod()}

Now all the other code works.

One comment so far
Testing Mixed Swift and Objective-C code Swift, Xcode 6, XCTestRon

Ive been working with a Swift project, and recently decided to add MMWormhole to it. This is the first Objective-C code to be added to this project, so I needed to review the Apple WWDC 2014 videos and developer documentation to figure out how to that.

It appears at first glance that the process is very simple. At least, it should be. What I ran into though appears to be bugs in Xcode.

The first bug I ran into was a problem with the prompt to automatically create the bridging header. When an Objective-C file is added to an all-Swift project, Xcode is supposed to ask you if youd like a bridging header to be created, and then do so. This didnt happen, but its no big deal. The bridging header can be easily created manually. This is pretty simple, but may not work depending on whether you hit the second bug I ran into, described further on.

Create a new header file. Name it -Bridging-Header.h (substituting with the name of your project)Search for the Objective-C Bridging Header setting, and set its value to point to the file just createdRepeat step 2 for the test target if youre going to do any testing that needs to reference the Objective-C code also. This shouldnt be necessary in most cases, but I needed to do so in order to write a unit test to try to catch the second bug.

The second bug is much worse. It appears that once a project starts getting bigger or more complex, the bridging header just stops working. By that I mean that the objects included using the bridging header (MMWormhole in my case) stop being found, even if previously building ok.

Im in the process of recreating my project to try to determine exactly what steps cause the bridging header to stop working. Ill update this post once Ive found it.

Update 3/11/15

A friend of mine ran into an issue when trying to test a Swift class that had been added to his otherwise Objective-C project. Since he already had a good suite of Objective-C tests, he simply wanted to add an Objective-C test. This caused various compile errors. The solution was to add the Swift file to the test target.

By default, tests are run as application tests. This means that the tests are injected into the application. Hence tests have access to everything in the application. However, Swift files are compiled into a separate module during the build process, and thus not visible to the test target. You can think of this as meaning that Swift files are in effect run as library tests, and thus must be added to the test target to be visible.

View all 2 comments
Manual Mocking in Swift Swift, Xcode 6, XCTestRon

Ive become a fan of creating ones own test doubles (aka mock objects) instead of using a mock framework like OCMock or OCMockito. Uncle Bob describes this process in one of his Clean Code videos, and it seems to work very well in Swift.

Why create your own mock objects? There are a couple reasons for doing this.

Tests can be more readable.
I say can because its really up to you to create readable mocks.You have nearly unlimited faking capability.
I say nearly because there are some things that may not be possible using class inheritance, for example overriding methods or properties that have been marked as final.

So lets take a look at using manually created fake doubles for testing a simple Power class. This class has one purpose: to report whether or not the device is plugged-in. The way this is done on an iOS device is by using the batteryState property of the UIDevice currentDevice singleton.

Uh-oh, did I just say singleton? Yep. Thats typically bad news for unit testing. However, this wont be a problem for us because were going to replace the UIDevice singleton with our own fake object. This means that well have to follow the tell, dont ask principle, and pass in the UIDevice object to our Power object instead of letting it ask for the singleton UIDevice currentDevice object.

class Power {   var device: UIDevice   init() {      self.device = UIDevice.currentDevice()   }   init(usingMockDevice mockDevice: UIDevice) {      device = mockDevice   }   func isPluggedIn() -gt; Bool {      let batteryState = self.device.batteryState      let isPluggedIn = batteryState ==    UIDeviceBatteryState.Charging || batteryState ==  UIDeviceBatteryState.Full      return isPluggedIn   }}

Here were using separate initializer methods to allow passing in a fake UIDevice object, or default to using the singleton currentDevice. Normal production code usage would look something like this:

   var power = Power()   ...   if power.isPluggedIn() {   ...

On the other hand, for testing this well create a test double and use it with the usingMockDevice initializer as shown here:

class mockPluggedInDevice: UIDevice {   override var batteryState: UIDeviceBatteryState {      return UIDeviceBatteryState.Full   }}
class PowerTests: XCTestCase {   func testPluggedInWhenBatteryFull() {      let mockDevice = mockPluggedInDevice()      let power = Power(usingMockDevice: mockDevice)      XCTAssertTrue(power.pluggedIn())   }}

So heres a question for you. In which file do we put the mockPluggedInDevice code? Im a bit conflicted on this. On one hand, I usually prefer to keep test code completely out of product code files. But on the other hand, mock objects are by nature going to be pretty dependent on the product code they are mocking, so I should probably keep it with the product code.

Clarification: For simplicity, I am using the term mock object to describe what would more accurately be called a stub. Martin Fowler clearly defines the difference in this 2007 article.

View all 2 comments
Asynchronous unit tests using XCTestExpectation UncategorizedRon

I came across an interesting blog post by Phil Beauvoir about Asynchronous Unit Testing in Xcode 6 using the new XCTestExpectation. It explains how he converted existing Objective-C asynchronous iOS unit tests to Swift, at the same time making them more efficient and readable by using an instance of XCTestExpectation and waitForExpectationsWithTimeout().

XCTestExpectation is a dirt simple class with 1 method: fulfill(). Create an instance of it and call fulfill() when the expectation has been met.

In your test assert section, call waitForExpectationsWithTimeout(), passing the XCTestExpectation, and Voila! Asynchronous unit tests.

As opposed to using a spin loop, this explicitly informs the XCTest framework that your test is waiting for an asynchronous event to happen, allowing it to perform other tests while waiting.

One comment so far
Testing Storyboards in Swift? storyboards, Swift, Xcode 6, XCTestRon

Awhile back I blogged about how to test storyboards by loading the ViewController from a Storyboard. Recently Ive been trying to figure out how to do the same thing in Swift.

Update: latest code appears to be working ok for testing view controllers as long as I dont try to run them on an actual iPhone device. When I do that, the test hangs.

The code and instructions posted by Mike Cole appear to almost work in Swift with the latest Xcode (Im using Xcode 6.2, but 6.1 works also). I had to also reference the ViewControllers view. Evidently the ViewController will lazy load the view, meaning that the outlets dont become connected until after ViewController.view is referenced.

Also, be careful what you put into your view controllers viewDidLoad method. Code that requires that the view is actually being displayed should be moved to viewWillDisplay or may cause the unit test to crash (since there isnt really a display during unit testing).

Example XCTest setup code to load a viewcontroller named MainVC from main.storyboard.

override func setUp() {  super.setUp()          let storyboard = UIStoryboard(name: Main, bundle: NSBundle(forClass: self.dynamicType))  vc = storyboard.instantiateViewControllerWithIdentifier(MainVC) as ViewController          let dummy = vc.view // force loading subviews and setting outlets          vc.viewDidLoad()}

Ive left the previous post below, but its basically outdated now. After running into various problems, I resorted to using Objective-C unit tests, and describe how to do so below. I wouldnt recommend doing so anymore, since Swift tests appear to work ok now.
After fumbling around for awhile with the Swift test case file, and not making much progress, I decided to try something different, and tried adding an Objective-C test case file to my Swift project. At least in this case, I know how to load the ViewController from the Storyboard. And this actually worked.

This turned out to be fairly simple. Let me warn you though, that I consider this approach to be a temporary hack, albeit an interesting one. I believe the correct solution will be to figure out how to do this in a Swift unit test case file. At this point though, Im not sure if Im being prevented from doing so due to bugs in beta level Xcode 6, or just my lack of Swift knowledge.

But caveat emptor aside, here is how to create an Objective-C unit test case file in an otherwise entirely Swift project, and use it to load and test a ViewController from a storyboard:

Set the product module name so that you will know the swift header file name to import (eg. #import ProductModuleName-swift.h). Note that this should not be necessary, as the Product Module Name is supposed to default to the Product Name. This wasnt working as of Beta 2.Add an Objective-C unit test case file. Make sure to set the language to Objective-C. It will default to Swift.I did not have to create an Objective-C Bridging  Header for the Swift ViewController, because Im only going the other way, from Swift to Objective-C, but I did anyways when prompted. I dont think having it will hurt anything, and you might want it later.Import the swift header file into the Objective-C unit test case file:
#import ProductModuleName-swift.h

That was it. This then gave me access to my ViewController definitions. Then use the previous described method of loading a storyboard and viewcontroller from it.

I will update this article once I figure out how to do it correctly in a Swift unit test case file.

View all 6 comments
Unit testing in Swift OCMockito, Swift, TDD, Xcode 6, XCTestRon

The iOS folks around here are all abuzz about the new Swift language announced by Apple this week. Surprisingly, this information was released publicly, so no NDA required to talk about it.  You can find the information at https://developer.apple.com/swift.

While there are still a lot of questions about the implications of testing in Swift, at first glance it looks pretty straight forward. One nice surprise, reported yesterday on BendyWorks.com, is that  Setup() isnt needed to create fresh instances of the object-under-test. Simply creating a as a constant stored property of the test case class results in a fresh instance being created for each test.

Ive run through some TDD katas using Swift, and after some initial adjustment to the new language, I have to say that things appear to work fairly well. Im really warming up to Swift.

Now the next question is whether or not the existing mock frameworks still work, or how soon we can get updates. No comment from Jon Reid yet, but Ill bet he will be speaking out soon

TAGS:about TDD unit Its iOS Unit Testing free 

<<< Thank you for your visit >>>

It's about TDD, unit testing, and creating bug free code on iOS.

Websites to related :
Applicant Tracking Software, Rec

  keywords:
description:Applicant Tracking Software, ATS Software, Recruitment Software, Onboarding Software, Careers Websites, Video Interviews, Recrui

Fresh N Marine | Best Online Aqu

  keywords:
description:Official Winner of Best Online Aquarium Store 2021 in Singapore & South East Asia. One Stop Aquarium Solutions Provider includin

Apartments for Rent in Cleveland

  keywords:
description:Rent One, Two & Three Bedroom Apartments in Cleveland that are Pet Friendly w/ Luxury Amenities & Spacious, Now Leasing, Call To

Jdorama.com : Japanese Drama Hom

  keywords:
description:JDorama.com is a site for fans of Japanese Drama (also called jdrama, jdorama or j-drama). It offers information on j-drama, rev

File Taxes Online | Free Tax Sof

  keywords:
description:
TaxAct × Tax Products Online Products Xpert Help Download Products

Mumble Music | Surveying Interna

  keywords:
description:Surveying International Music
Mumble Music Search Primary Menu Skip to content MusicTheatreComedyFesti

The Inter Faith Network (IFN)

  keywords:
description:
The Inter Faith Network Inter Faith Week

▷ gh.Sjtu.edu.cn Website statis

  keywords:
description:ℹ️ Sjtu - Get extensive information about the hostname including website and web server details, IP addresses, DNS resource reco

California's Stem Cell Agency |

  keywords:
description:CIRM funds promising stem cell research in California to accelerate stem cell treatments to patients with unmet medical needs.

Jdorama.net : jdorama - HypeStat

  keywords:
description:jdorama.net receives about 3 unique visitors per day, and it is ranked 14,503,302 in the world. jdorama.net uses n/a web technol

ads

Hot Websites