Skip to content

Instantly share code, notes, and snippets.

@joemasilotti
Created March 27, 2016 20:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joemasilotti/da1c5a04bd6386c22d55 to your computer and use it in GitHub Desktop.
Save joemasilotti/da1c5a04bd6386c22d55 to your computer and use it in GitHub Desktop.
AddressFormatter in Swift
import CoreLocation
struct AddressFormatter {
private let placemark: Placemarkable
init(placemark: Placemarkable) {
self.placemark = placemark
}
func formattedAddress() -> String {
let nameOrAddress = placemark.name ?? placemark.thoroughfare
var city = placemark.locality
var state = placemark.administrativeArea
let zip = placemark.postalCode
var cityAndState: String?
if let presentCity = city, presentState = state {
cityAndState = "\(presentCity), \(presentState)"
city = nil
state = nil
}
let presentInfo = [nameOrAddress, city, state, cityAndState, zip].flatMap{$0}
return presentInfo.joinWithSeparator(" ")
}
}
import XCTest
import CoreLocation
class AddressFormatterTests: XCTestCase {
var subject: AddressFormatter!
func test_WithAName_ReturnJustTheName() {
let placemark = MockPlacemarkable()
placemark.name = "St. Gambrinus Beer Shoppe"
subject = AddressFormatter(placemark: placemark)
XCTAssertEqual(subject.formattedAddress(), "St. Gambrinus Beer Shoppe")
}
func test_WithoutANameButWithAnAddress_ReturnJustTheAddress() {
let placemark = MockPlacemarkable()
placemark.thoroughfare = "533 Atlantic Ave"
subject = AddressFormatter(placemark: placemark)
XCTAssertEqual(subject.formattedAddress(), "533 Atlantic Ave")
}
func test_WithANameAndACity_ReturnBoth() {
let placemark = MockPlacemarkable()
placemark.name = "St. Gambrinus Beer Shoppe"
placemark.locality = "Brooklyn"
subject = AddressFormatter(placemark: placemark)
XCTAssertEqual(subject.formattedAddress(), "St. Gambrinus Beer Shoppe Brooklyn")
}
func test_WithACityAndState_IncludesThemWithAComma() {
let placemark = MockPlacemarkable()
placemark.locality = "Brooklyn"
placemark.administrativeArea = "NY"
subject = AddressFormatter(placemark: placemark)
XCTAssertEqual(subject.formattedAddress(), "Brooklyn, NY")
}
func test_WithAStateButNoCity_DoesNotIncludeAComma() {
let placemark = MockPlacemarkable()
placemark.administrativeArea = "NY"
subject = AddressFormatter(placemark: placemark)
XCTAssertEqual(subject.formattedAddress(), "NY")
}
func test_WithAOptionalParameters_IncludesThem() {
let placemark = MockPlacemarkable()
placemark.thoroughfare = "533 Atlantic Ave"
placemark.locality = "Brooklyn"
placemark.administrativeArea = "NY"
placemark.postalCode = "11217"
subject = AddressFormatter(placemark: placemark)
XCTAssertEqual(subject.formattedAddress(), "533 Atlantic Ave Brooklyn, NY 11217")
}
}
import Foundation
@objc class MockPlacemarkable: NSObject, Placemarkable {
var name: String?
var thoroughfare: String?
var administrativeArea: String?
var locality: String?
var postalCode: String?
}
@Aghassi
Copy link

Aghassi commented Mar 27, 2016

In each of your tests you create this. I would save some code and instead do:

let placemark = MockPlacemarkable()
func setup() {
    placemark = MockPlacemarkable()    // resets placemark before each new test
    XCTAssertNotNil(placemark, "Something has gone terribly wrong, placemark should not be nil before running a test")
}

This way, we guarantee that we always have a placemark, and that it is never nil before a test. We also clean up the first line of all the tests by removing the let placemark = MockPlacemarkable()

@Aghassi
Copy link

Aghassi commented Mar 27, 2016

Do a test for placemark.name too because in your formattedAddress() function you test let nameOrAddress = placemark.name ?? placemark.thoroughfare. You may also want to test what happens when you pass both name and thoroughfare in, just in case. The ?? operator shouldn't change, but if it does you will know.

@Aghassi
Copy link

Aghassi commented Mar 27, 2016

Suggestion, since you seem to be using the same address (or parts of it) to test throughout, maybe consider abstracting them to variables at the top, or a expectedPlacemark variable. This way, when you are testing, you set it to something that isn't changing (and prevent typos from occurring in the future). Also, means when you test the comparison, you just format the concatenation of two strings, instead of possibility of miss typing a full string.

@joemasilotti
Copy link
Author

@Aghassi thanks for the review!

Comment 1: Good idea pulling the placemark out to a let variable. Fortunately, the code in setup isn't needed. The class is recreated by XCTest for each test, so no pollution would occur.

Comment 2: The first test covers just name, right? But I can definitely add a test that checks both, good point.

Comment 3: I like the idea of abstracting comparisons, but an expected placemark seems too heavy handed. Making the strings, however, be variables could be a good compromise.

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