Xctest Unit Test Data Response Not Set in Test After Viewdidload

XCTest Unit Test data response not set in test after viewDidLoad

Problem

On the second Assertion you expect data which are loaded asynchronously, but you check them synchronously and at the time you are checking for them, the network operation has not finished yet, so of course it is going to fail.

Solution

Testing asynchronously is available on iOS using XCTestExpectation.

Example of use

let testExpectation = expectation(description: "Asynchronous expectation")
let sut = SubjectUnderTest()

sut.executeAsynchronousOperation(completion: { (error, data) in
XCTAssertTrue(error == nil)
XCTAssertTrue(data != nil)

testExpectation.fulfill()
})

waitForExpectations(timeout: 5, handler: .none)

Tips

Another thing to point out is that testing network operations and waiting for the response is a bad practice, you should intercept the network requests and return local data instead of waiting for the real data from the server. (On GitHub there is a nice framework to do that in Swift: OHHTTPStubs)

How to unit test `viewDidLoad()`

Why do you need to use the storyboard to create the view controller?

Wouldn't this work?

func testThatServiceIsCalled() {
let vc = MyViewController()
vc.service = serviceMock
vc.viewDidLoad()

XCTAssertTrue(serviceMock.loadCalled)
}

UnitTests and iOS : viewDidLoad triggered twice

You need to access the view in order to have it load automatically.

You can use something like this to do it without side effects:

vc.view.hidden = NO; // Or YES if it is supposed to be hidden.

Oh, and then remove your manual call to viewDidLoad as it won't be needed.

IOS Why Unit Test a class calls ViewController

It's creating an instance of ViewController because your app creates a ViewController at launch, and your test bundle uses your app as its “Host Application”:

host application setting

When the setting is configured like shown above, it means Xcode runs the tests in your test bundle by launching the host application, then injecting the test bundle into it.

You can change the “Host Application” setting to “None”:

host application set to none

When the setting is configured as “None”, Xcode runs your test bundle using a non-GUI app called the XCTest agent, and doesn't launch your app, so your app doesn't get the chance to create a ViewController.

Note that when you set “Host Application” to “None”, your test bundle can no longer access any APIs defined in the application. Any APIs you want to test, you have to move into a framework, and link the test bundle with that framework (in the “Build Phases” tab for the test bundle).

Note also that even when you set “Host Application” to “None”, Xcode still launches a simulator. Your test cases are allowed to use iOS system services that are only available when a simulator is running, and Xcode doesn't know in advance whether your test cases need those services. So it has to launch the simulator first, just in case.

Use of undeclared type 'ViewController' when unit testing my own ViewController in Swift?

Swift 1

You should add ViewController.swift file's target membership also as your test target also if you are not using framework. Select class file add to target as shown in image:

Sample Image

OR

If you are ViewController is within a framework : ViewController class is in different target and You are not declaring class with public access level. By default Classes are internal (Accessible within a target). Declare it as public and also make methods or properties as public if you want to access it i.e

public class ViewController: UIViewController {

public var content: String!

override public func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}

override public func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

}

Swift 2 Update

In your test target, just import the module you want to test using the @testable keyword:

@testable import moduleToTest

You can now access public and internal symbols in your test target.

swift 2 Xcode 7 unit testing

Unit Test button added to view

The viewDidLoad is not called in your test case, therefore it fails. You have to call it manually.

1. Introduce an extension

    extension UIViewController {

func startViewLifecycle() {
view.setNeedsLayout()
view.layoutIfNeeded()
}
}

2. Call it in your test case:

func testAddRoomButtonInRoomsViewController() {
let vc = myViewController()
vc.startViewLifecycle()

XCTAssertNotNil(vc.myButton, "Button Not Initialised")
XCTAssertNotNil(vc.myButton.superview, "Button Not Added To View")
}


Related Topics



Leave a reply



Submit