Mock and inject ObservableObject

Viewed 553

I have a class Foo that has multiple dependencies to ObservableObject. For testing purposes I want to create a mocked version of those objects but I cannot see a way to do so and then inject those into Foo.

  • I can't create another protocol that my ObservableObject implements because the ObservableObject protocol has self or associated type requirements and can't be used as a type declared and
  • I cannot subclass the ObservableObject since it has @Published property wrapped members that cannot be overwritten.
1 Answers

At the moment the only way I see is to write a mock subscriber that is subscribing to the ObservableObject:

final class SomeState: ObservableObject {
  @Published var someValue: String?
}

If the ObservableObject looks like this you could implement the mock subscriber (I call them Watcher) like this:

final class SomeStateWatcher {
  let someState: SomeState

  var didSetSomeValue: Bool = false
  var lastSomeValue: String?

  private var someValueSubscriber: AnyCancellable?

  init(someState: SomeState) {
    self.someState = someState

    self.someValueSubscriber = self.someState.$someValue
      .sink(receiveValue: { value in 
        self.didSetSomeValue = true
        self.lastSomeValue = value
      })
  }
}

func testDoStuffThatChangesTheLocalSomeStateProperty() {
  someImplementation.doStuffThatChangesTheLocalSomeStateProperty(with: "Fourty2")

  XCTAssertTrue(someStateWatcher.didSetSomeValue, "It should have published someValue")
  XCTAssertEqual(someStateWatcher.lastSomeValue, "Fourty2", "It should have published the correct value)
}
Related