I'm used to wait for expectations when using XCTest, but I'm completely stumped by the seemingly-absent option for expecting some parts of my code to be called in Swift Testing 🤔
Consider the following:
protocol MyAPI {
func getData() async throws -> String
}
class MockAPI: MyAPI {
let stub: () async throws -> String
init(stub: @escaping () async throws -> String = { "hello" }) {
self.stub = stub
}
func getData() async throws -> String {
try await stub()
}
}
Which is being used in my view model:
class MyViewModel: ObservableObject {
private let api: MyAPI
@Published
var data: String
init(api: MyAPI) {
self.api = api
}
func refresh() async throws {
self.data = try await api.getData()
}
}
When I wrote tests in the past, I would simply override the stub of the MockAPI implementation and fulfill an expectation in there:
class MyViewModelTests: XCTestCase {
func testModelCallsAPIOnRefresh() async throws {
let expectCallsAPI = expectation("Model should call API")
let api = MockAPI {
expectCallsAPI.fulfill()
return "hello"
}
let model = MyViewModel(api: api)
try await model.refresh()
await fulfillment(of: [expectCallsAPI], timeout: 1)
}
}
How would I go about checking that my model does indeed call the API when using Swift Testing?
Post
Replies
Boosts
Views
Activity
The interface for the KeyedDecodingContainer protocol declares a bunch of requirements like such:
func decode(_ type: Bool.Type, forKey key: Self.Key) throws -> Bool
func decode(_ type: String.Type, forKey key: Self.Key) throws -> String
func decode(_ type: Double.Type, forKey key: Self.Key) throws -> Double
// etc.
As well as a generic one:
func decode<T>(_ type: T.Type, forKey key: Self.Key) throws -> T where T : Decodable
Is that done for performance reasons?
I have implemented a return-type-aware generic extension on KeyedDecodingContainer which always defers to the aforementioned generic implementation:
func decode<Value: Decodable>(
type: Value.Type = Value.self,
_ key: Key
) throws -> Value {
try decode(type, forKey: key)
}
Which allows me to decode anything in the following way:
self.myValue = container.decode(.myValue)
// instead of
self.myValue = container.decode(String.self, forKey: .myValue)
Now, this works fine and all, but upon submitting this extension for code review, one of my colleague raised concerns for defaulting to calling only the generic implementation rather than the statically-typed one (where applicable).
So, my question is, are these concerns valid?
On iOS 15.1, downloaded a new TestFlight build, and whatever I do I cannot get the feedback sharing options after taking a screenshot... This is being reported to us by some of our testers, and I have confirmed this happens for at least another developer working in a different company...
Anyone else run into this?