Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ccabanero/0f20b0708c0d756327995e58ff3309d4 to your computer and use it in GitHub Desktop.
Save ccabanero/0f20b0708c0d756327995e58ff3309d4 to your computer and use it in GitHub Desktop.
Sample iOS Unit Tests: Working with a ViewController composed of UISearchBar
import XCTest
@testable import YourProjectModule
class ViewControllerTest: XCTestCase {
var systemUnderTest: ViewController!
override func setUp() {
super.setUp()
//get the storyboard the ViewController under test is inside
let storyboard: UIStoryboard = UIStoryboard(name: "Main_iPhone", bundle: nil)
//get the ViewController we want to test from the storyboard (note the identifier is the id explicitly set in the identity inspector)
systemUnderTest = storyboard.instantiateViewControllerWithIdentifier("ViewController") as! ViewController
//load view hierarchy
_ = systemUnderTest.view
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testSUT_CanBeInstantiated() {
XCTAssertNotNil(systemUnderTest)
}
// MARK: - SearchBar
func testSUT_HasSearchBar() {
XCTAssertNotNil(systemUnderTest.searchBar)
}
func testSUT_ShouldSetSearchBarDelegate() {
XCTAssertNotNil(self.systemUnderTest.searchBar.delegate)
}
func testSUT_ConformsToSearchBarDelegateProtocol() {
XCTAssert(systemUnderTest.conformsToProtocol(UISearchBarDelegate))
XCTAssertTrue(self.systemUnderTest.respondsToSelector(#selector(systemUnderTest.searchBarTextDidBeginEditing(_:))))
XCTAssertTrue(self.systemUnderTest.respondsToSelector(#selector(systemUnderTest.searchBarSearchButtonClicked(_:))))
}
// MARK: - Search Auto-Suggest Behavior
func testSUT_CanProperlyDisplay_CityState_AutoSuggestionsInTableView_AfterSearchTextChanges() {
// sample of searchable items (instead of fetching asynchronously from network)
systemUnderTest.allItems = ["Lincoln, NE", "Los Angeles, CA", "Louisville, KY"]
// simulate user typing in Search text and confirm results ...
systemUnderTest.searchBar(systemUnderTest.searchBar, textDidChange: "L")
XCTAssertEqual(systemUnderTest.displayItems.count, 3)
XCTAssertEqual(systemUnderTest.displayItems[0], "Lincoln, NE")
XCTAssertEqual(systemUnderTest.displayItems[1], "Los Angeles, CA")
XCTAssertEqual(systemUnderTest.displayItems[2], "Louisville, KY")
systemUnderTest.searchBar(systemUnderTest.searchBar, textDidChange: "Lo")
XCTAssertEqual(systemUnderTest.displayItems.count, 2)
XCTAssertEqual(systemUnderTest.displayItems[0], "Los Angeles, CA")
XCTAssertEqual(systemUnderTest.displayItems[1], "Louisville, KY")
systemUnderTest.searchBar(systemUnderTest.searchBar, textDidChange: "Lou")
XCTAssertEqual(systemUnderTest.displayItems.count, 1)
XCTAssertEqual(systemUnderTest.displayItems[0], "Louisville, KY")
}
func testSUT_CanProperlyDisplay_ZipCode_AutoSuggestionsInTableView_AfterSearchTextChanges() {
// sample of searchable items (instead of fetching asynchronously from network)
systemUnderTest.allItems = ["98199", "98122", "98012"]
// simulate user typing in Search text and confirm results ...
systemUnderTest.searchBar(systemUnderTest.searchBar, textDidChange: "9")
XCTAssertEqual(systemUnderTest.displayItems.count, 3)
XCTAssertEqual(systemUnderTest.displayItems[0], "98199")
XCTAssertEqual(systemUnderTest.displayItems[1], "98122")
XCTAssertEqual(systemUnderTest.displayItems[2], "98012")
systemUnderTest.searchBar(systemUnderTest.searchBar, textDidChange: "981")
XCTAssertEqual(systemUnderTest.displayItems.count, 2)
XCTAssertEqual(systemUnderTest.displayItems[0], "98199")
XCTAssertEqual(systemUnderTest.displayItems[1], "98122")
systemUnderTest.searchBar(systemUnderTest.searchBar, textDidChange: "9812")
XCTAssertEqual(systemUnderTest.displayItems.count, 1)
XCTAssertEqual(systemUnderTest.displayItems[0], "98122")
}
func testSUT_CanAddSelectedSearchItem_FromTableView_ToSearchBarText() {
// sample of searchable items (instead of fetching asynchronously from network)
systemUnderTest.allItems = ["Lincoln, NE", "Los Angeles, CA", "Louisville, KY"]
// simulate user typing in Search text for "L"
systemUnderTest.searchBar(systemUnderTest.searchBar, textDidChange: "L")
// simulate tapping on the first auto-suggest item (i.e. first cell in tableview)
systemUnderTest.tableView(self.systemUnderTest.tableView, didSelectRowAtIndexPath: NSIndexPath(forRow: 0, inSection: 0))
let expectedSearchBarText = "Lincoln, NE"
let actualSearchBarText = systemUnderTest.searchBar.text
XCTAssertEqual(expectedSearchBarText, actualSearchBarText)
}
// MARK: - Search Text Processing
func testSUT_DefinesTargetSearchText_AfterSearchButtonTapped() {
// simulate user entering search text in search bar
systemUnderTest.searchBar.text = "Seattle, WA"
// simulate user tapping 'search' button on keyboard
systemUnderTest.searchBarSearchButtonClicked(systemUnderTest.searchBar)
let expectedTargetSearchText = "Seattle, WA"
let actualTargetSearchText = systemUnderTest.targetSearchText
XCTAssertEqual(expectedTargetSearchText, actualTargetSearchText)
}
func testSUT_DerivesTrimmedTargetSearchText_AfterSearchButtonTapped() {
systemUnderTest.searchBar.text = " Seattle, WA "
systemUnderTest.searchBarSearchButtonClicked(systemUnderTest.searchBar)
let expectedTargetSearchText = "Seattle, WA"
let actualTargetSearchText = systemUnderTest.targetSearchText
XCTAssertEqual(expectedTargetSearchText, actualTargetSearchText)
}
// continue with more tests related to your App ...
}
@jamorat
Copy link

jamorat commented Oct 10, 2017

Why do you load the view hierarchy but do nothing with it? As in:

//load view hierarchy
_ = systemUnderTest.view

I am sure you are doing it for a reason, I am just wondering what the reason is so that I can use the technique in my own tests if it is helpful. Thank you!

Update: I ran the following test on a project I made:

func test_userPosts_tableViewDelegateNotNil(){
XCTAssertNotNil(userPostsViewController.tableView.delegate)
}

And it resulted in a bad execution error until I used the technique:
_ = userPostsViewController.view

What is happening here with that call?

@jitccgcg
Copy link

jitccgcg commented Aug 30, 2018

_ = userPostsViewController.view is simply to force the view to be loaded and viewDidLoad() to be called.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment