How to mock certain classes with Swift Testing?

I'm new to swift testing. How do I mock certain classes so that it would simulate a certain behaviour?

For example, in my code it references the current time via Date(). In order for my test cases to pass I need to pretend the current time is X. How can I do that?

1 Like

Hi! If you search the Swift forums, you'll see a number of posts about mocking in Swift. :smile: Because Swift is statically typed, mocking as a general concept isn't really supported for value types. Date (from Foundation) is a value type, meaning it's basically just bits in memory—there's no place to put hooks for injecting test-time code.

We generally recommend using protocols for behaviour that may be dynamically selected at runtime. For instance, let's say you wanted to mock Date's timeIntervalSince1970 property. You could create a protocol with this member, add conformance to Date, add conformance to your mock type, and then have your business logic accept an instance of T: TheProtocol instead of just Date:

protocol HasTimeIntervalSince1970 {
  var timeIntervalSince1970: TimeInterval { get }
}

extension Date: HasTimeIntervalSince1970 {}

struct MockDate: HasTimeIntervalSince1970 {
  var timeIntervalSince1970: TimeInterval
}

func doSomeWork(with date: some HasTimeIntervalSince1970) -> Bool {
  if date.timeIntervalSince1970 < YEAR_2024 {
    print("It's the wrong year!")
    return false
  }
  // ...
  return true
}

@Test func testSomeWork() {
  let mockDate = MockDate(timeIntervalSince1970: ...)
  #expect(doSomeWork(with: mockDate))
}

There are many solutions here, and one has been provided. However, abstracting everything through a protocol is deeply inefficient and unnecessary in many instances. For simple cases, injecting values directly can work, so instead of creating a Date() directly, you'd simply have a parameter like now: Date = Date() which can inject any Date and use that. Another solution would be abstracting things through a closure interface, which acts sort of like a protocol implementation without the overhead of the protocol definition. You could have a var now: () -> Date closure some where which is usually { Date() } but which can be overridden to provide a different value. Personally I like the swift-dependencies which provides a place for things like that to live, and easy ways to scope dependencies within your app. And if you need, you can even vend protocol interfaces though it. The library also recently shipped integration with swift-testing, so you can set dependencies at the @Suite level.