Skip to content

Commit 9a22c5a

Browse files
authored
Test store dependency binding (#1620)
* Bind dependencies when constructing test store and when asserting. * clean up * clean up; * feedback
1 parent 3bfbc7f commit 9a22c5a

File tree

2 files changed

+49
-10
lines changed

2 files changed

+49
-10
lines changed

Sources/ComposableArchitecture/TestStore.swift

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -564,8 +564,9 @@ open class TestStore<State, Action, ScopedState, ScopedAction, Environment> {
564564
/// - initialState: The state the feature starts in.
565565
/// - reducer: The reducer that powers the runtime of the feature.
566566
public init<Reducer: ReducerProtocol>(
567-
initialState: State,
567+
initialState: @autoclosure () -> State,
568568
reducer: Reducer,
569+
prepareDependencies: (inout DependencyValues) -> Void = { _ in },
569570
file: StaticString = #file,
570571
line: UInt = #line
571572
)
@@ -576,6 +577,11 @@ open class TestStore<State, Action, ScopedState, ScopedAction, Environment> {
576577
Action == ScopedAction,
577578
Environment == Void
578579
{
580+
var dependencies = DependencyValues()
581+
dependencies.context = .test
582+
prepareDependencies(&dependencies)
583+
let initialState = DependencyValues.$_current.withValue(dependencies) { initialState() }
584+
579585
let reducer = TestReducer(Reduce(reducer), initialState: initialState)
580586
self._environment = .init(wrappedValue: ())
581587
self.file = file
@@ -585,6 +591,7 @@ open class TestStore<State, Action, ScopedState, ScopedAction, Environment> {
585591
self.store = Store(initialState: initialState, reducer: reducer)
586592
self.timeout = 100 * NSEC_PER_MSEC
587593
self.toScopedState = { $0 }
594+
self.dependencies = dependencies
588595
}
589596

590597
@available(
@@ -1033,7 +1040,9 @@ extension TestStore where ScopedState: Equatable {
10331040
case .on:
10341041
var expectedWhenGivenPreviousState = expected
10351042
if let updateStateToExpectedResult = updateStateToExpectedResult {
1036-
try updateStateToExpectedResult(&expectedWhenGivenPreviousState)
1043+
try DependencyValues.$_current.withValue(self.dependencies) {
1044+
try updateStateToExpectedResult(&expectedWhenGivenPreviousState)
1045+
}
10371046
}
10381047
expected = expectedWhenGivenPreviousState
10391048

@@ -1046,7 +1055,9 @@ extension TestStore where ScopedState: Equatable {
10461055
case .off:
10471056
var expectedWhenGivenActualState = actual
10481057
if let updateStateToExpectedResult = updateStateToExpectedResult {
1049-
try updateStateToExpectedResult(&expectedWhenGivenActualState)
1058+
try DependencyValues.$_current.withValue(self.dependencies) {
1059+
try updateStateToExpectedResult(&expectedWhenGivenActualState)
1060+
}
10501061
}
10511062
expected = expectedWhenGivenActualState
10521063

@@ -1058,10 +1069,12 @@ extension TestStore where ScopedState: Equatable {
10581069
&& expectedWhenGivenActualState == actual
10591070
{
10601071
var expectedWhenGivenPreviousState = current
1061-
if let modify = updateStateToExpectedResult {
1072+
if let updateStateToExpectedResult = updateStateToExpectedResult {
10621073
_XCTExpectFailure(strict: false) {
10631074
do {
1064-
try modify(&expectedWhenGivenPreviousState)
1075+
try DependencyValues.$_current.withValue(self.dependencies) {
1076+
try updateStateToExpectedResult(&expectedWhenGivenPreviousState)
1077+
}
10651078
} catch {
10661079
XCTFail(
10671080
"""
@@ -2059,11 +2072,7 @@ public struct TestStoreTask: Hashable, Sendable {
20592072

20602073
class TestReducer<State, Action>: ReducerProtocol {
20612074
let base: Reduce<State, Action>
2062-
var dependencies = { () -> DependencyValues in
2063-
var dependencies = DependencyValues()
2064-
dependencies.context = .test
2065-
return dependencies
2066-
}()
2075+
var dependencies = DependencyValues()
20672076
let effectDidSubscribe = AsyncStream<Void>.streamWithContinuation()
20682077
var inFlightEffects: Set<LongLivingEffect> = []
20692078
var receivedActions: [(action: Action, state: State)] = []

Tests/ComposableArchitectureTests/TestStoreTests.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,4 +264,34 @@ final class TestStoreTests: XCTestCase {
264264

265265
store.send(true) { $0 = 1 }
266266
}
267+
268+
func testDependenciesEarlyBinding() async {
269+
struct Feature: ReducerProtocol {
270+
struct State: Equatable {
271+
var count = 0
272+
var date: Date
273+
init() {
274+
@Dependency(\.date.now) var now: Date
275+
self.date = now
276+
}
277+
}
278+
func reduce(into state: inout State, action: Void) -> EffectTask<Void> {
279+
state.count += 1
280+
return .none
281+
}
282+
}
283+
284+
let store = TestStore(
285+
initialState: Feature.State(),
286+
reducer: Feature()
287+
) {
288+
$0.date = .constant(Date(timeIntervalSince1970: 1234567890))
289+
}
290+
291+
await store.send(()) {
292+
@Dependency(\.date.now) var now: Date
293+
$0.count = 1
294+
$0.date = now
295+
}
296+
}
267297
}

0 commit comments

Comments
 (0)