-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(test): add unit tests for PlacesService and model validation
- Implement XCTest test cases for PlacesService with mock URLSession - Add Codable conformance tests for Place models - Set up mock network response handling - Fix PlacesResponse Codable implementation
- Loading branch information
Showing
4 changed files
with
200 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import XCTest | ||
@testable import taco_about_it_ios | ||
|
||
final class ModelTests: XCTestCase { | ||
|
||
func testDisplayNameCodable() throws { | ||
// Given | ||
let original = DisplayName(text: "Test Place") | ||
|
||
// When | ||
let encoded = try JSONEncoder().encode(original) | ||
let decoded = try JSONDecoder().decode(DisplayName.self, from: encoded) | ||
|
||
// Then | ||
XCTAssertEqual(original.text, decoded.text) | ||
} | ||
|
||
func testPlaceCodable() throws { | ||
// Given | ||
let original = Place( | ||
id: "test-id", | ||
displayName: DisplayName(text: "Test Place"), | ||
formattedAddress: "123 Test St", | ||
rating: 4.5, | ||
userRatingCount: 100 | ||
) | ||
|
||
// When | ||
let encoded = try JSONEncoder().encode(original) | ||
let decoded = try JSONDecoder().decode(Place.self, from: encoded) | ||
|
||
// Then | ||
XCTAssertEqual(original.id, decoded.id) | ||
XCTAssertEqual(original.displayNameText, decoded.displayNameText) | ||
} | ||
|
||
func testPlacesResponseCodable() throws { | ||
// Given | ||
let place = Place( | ||
id: "test-id", | ||
displayName: DisplayName(text: "Test Place"), | ||
formattedAddress: "123 Test St", | ||
rating: 4.5, | ||
userRatingCount: 100 | ||
) | ||
let original = PlacesResponse(places: [place]) | ||
|
||
// When | ||
let encoded = try JSONEncoder().encode(original) | ||
print(String(data: encoded, encoding: .utf8) ?? "") // For debugging | ||
let decoded = try JSONDecoder().decode(PlacesResponse.self, from: encoded) | ||
|
||
// Then | ||
XCTAssertEqual(original.places.count, decoded.places.count) | ||
XCTAssertEqual(original.places[0].id, decoded.places[0].id) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import XCTest | ||
@testable import taco_about_it_ios | ||
|
||
class URLProtocolMock: URLProtocol { | ||
static var requestHandler: ((URLRequest) throws -> (HTTPURLResponse, Data))? | ||
|
||
override class func canInit(with request: URLRequest) -> Bool { | ||
return true | ||
} | ||
|
||
override class func canonicalRequest(for request: URLRequest) -> URLRequest { | ||
return request | ||
} | ||
|
||
override func startLoading() { | ||
guard let handler = URLProtocolMock.requestHandler else { | ||
XCTFail("Handler is unavailable.") | ||
return | ||
} | ||
|
||
do { | ||
let (response, data) = try handler(request) | ||
client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed) | ||
client?.urlProtocol(self, didLoad: data) | ||
client?.urlProtocolDidFinishLoading(self) | ||
} catch { | ||
client?.urlProtocol(self, didFailWithError: error) | ||
} | ||
} | ||
|
||
override func stopLoading() {} | ||
} | ||
|
||
final class PlacesServiceTests: XCTestCase { | ||
var sut: PlacesService! | ||
var mockURLSession: URLSession! | ||
|
||
override func setUp() { | ||
super.setUp() | ||
|
||
// Configure mock URLSession | ||
let configuration = URLSessionConfiguration.ephemeral | ||
configuration.protocolClasses = [URLProtocolMock.self] | ||
mockURLSession = URLSession(configuration: configuration) | ||
|
||
sut = PlacesService(urlSession: mockURLSession) | ||
} | ||
|
||
override func tearDown() { | ||
sut = nil | ||
mockURLSession = nil | ||
URLProtocolMock.requestHandler = nil | ||
super.tearDown() | ||
} | ||
|
||
func testFetchPlacesWithValidLocation() async throws { | ||
// Given | ||
let location = GeoLocation(latitude: 37.7749, longitude: -122.4194) | ||
|
||
// Create a PlacesResponse object | ||
let mockPlacesResponse = PlacesResponse(places: [ | ||
Place( | ||
id: "test-id", | ||
displayName: DisplayName(text: "Test Taco Place"), | ||
formattedAddress: "123 Test St", | ||
rating: 4.5, | ||
userRatingCount: 100 | ||
) | ||
]) | ||
|
||
// Encode the response | ||
let mockData = try JSONEncoder().encode(mockPlacesResponse) | ||
|
||
let mockHTTPResponse = HTTPURLResponse( | ||
url: URL(string: "https://your-backend-url.com/places")!, | ||
statusCode: 200, | ||
httpVersion: nil, | ||
headerFields: ["Content-Type": "application/json"] | ||
)! | ||
|
||
// Set up the mock handler | ||
URLProtocolMock.requestHandler = { request in | ||
return (mockHTTPResponse, mockData) | ||
} | ||
|
||
// When | ||
let places = try await sut.fetchPlaces(location: location) | ||
|
||
// Then | ||
XCTAssertEqual(places.count, 1) | ||
XCTAssertEqual(places[0].id, "test-id") | ||
XCTAssertEqual(places[0].displayNameText, "Test Taco Place") | ||
} | ||
} |