Change the dependency (via init injection) on the fly in the unit test #1838
Replies: 3 comments 1 reply
-
Hi @jeffersonsetiawan, unfortunately it is not easy to swap out dependencies in the middle of a test if you are using the explicit, environment-style of dependencies. Is there a reason you can't use the new dependency system? My personal recommendation is to try to get to the let reducer = Lazy(
environment: MyEnvironment.mockFailed,
reducer: MyFeature.init(environment:)
}
func testTryAgainAfterErrorLoadingPage() {
let testStore = TestStore(
initialState: MyState(),
reducer: reducer
)
// ...
reducer.environment.loadData = { Effect(value: .success(1)) }
// ...
} |
Beta Was this translation helpful? Give feedback.
-
Hi @jeffersonsetiawan, unfortunately it is not easy to swap out dependencies in the middle of a test if you are using the explicit, environment-style of dependencies. Is there a reason you can't use the new dependency system? My personal recommendation is to try to get to the let reducer = Lazy(
environment: MyEnvironment.mockFailed,
reducer: MyFeature.init(environment:)
}
func testTryAgainAfterErrorLoadingPage() {
let testStore = TestStore(
initialState: MyState(),
reducer: reducer
)
// ...
reducer.environment.loadData = { Effect(value: .success(1)) }
// ...
} |
Beta Was this translation helpful? Give feedback.
-
Hi @mbrandonw internal final class OnTheFlyInjectionReducer<Base: ReducerProtocol, Environment>: ReducerProtocol {
internal var environment: Environment
private let create: (Environment) -> Base
internal init(
enviroment: Environment,
reducer create: @escaping (Environment) -> Base
) {
self.environment = enviroment
self.create = create
}
@inlinable
internal func reduce(into state: inout Base.State, action: Base.Action) -> Effect<Base.Action> {
self.create(environment).reduce(into: &state, action: action)
}
} using above implementation, we can do swap out our environment in the middle of a test. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi, I really love this architecture, I've used the TCA since the day 1.
Since the release of ReducerProtocol, I've experience "possible" difficulty on changing the dependency on the fly in a single unit test flow.
In ReducerProtocol, we have 2 differents way to inject our dependency/environment. First is from Dependency property wrapper, and the other one is inject it on the init (more like the old environment style of original TCA)
Let see this example code in the original style of TCA:
In that test, I change the return value of
loadData
viastore.environment.loadData
before tapping the try again button, so the return value after tapping the try again button will be changed.I can use the similar approach when using environment via the Dependency property wrapper.
Using first approach, we can modify the response of loadData on the fly via
testStore.dependencies.myEnvironment.loadData
But for the second approach, it's not as straight forward to change the response on the fly, as the reducer is value type and we can't know the type of the reducer inside the TestStore.
What I am thinking about how to change it on the fly is by using a flag to flip the response like this:
Is there easier way to change the response of the Environment via the init than this?
Thank you 🙏🏻
Beta Was this translation helpful? Give feedback.
All reactions