@@ -82,10 +82,17 @@ is a good chance you can immediately make use of one. If you are using `Date()`,
82
82
this library.
83
83
84
84
``` swift
85
- final class FeatureModel : ObservableObject {
85
+ @Observable
86
+ final class FeatureModel {
87
+ var items: [Item] = []
88
+
89
+ @ObservationIgnored
86
90
@Dependency (\.continuousClock ) var clock // Controllable way to sleep a task
91
+ @ObservationIgnored
87
92
@Dependency (\.date .now ) var now // Controllable way to ask for current date
93
+ @ObservationIgnored
88
94
@Dependency (\.mainQueue ) var mainQueue // Controllable scheduling on main queue
95
+ @ObservationIgnored
89
96
@Dependency (\.uuid ) var uuid // Controllable UUID creation
90
97
91
98
// ...
@@ -96,16 +103,17 @@ Once your dependencies are declared, rather than reaching out to the `Date()`, `
96
103
directly, you can use the dependency that is defined on your feature's model:
97
104
98
105
``` swift
99
- final class FeatureModel : ObservableObject {
106
+ @Observable
107
+ final class FeatureModel {
100
108
// ...
101
109
102
110
func addButtonTapped () async throws {
103
- try await self . clock .sleep (for : .seconds (1 )) // 👈 Don't use 'Task.sleep'
104
- self . items .append (
111
+ try await clock.sleep (for : .seconds (1 )) // 👈 Don't use 'Task.sleep'
112
+ items.append (
105
113
Item (
106
- id : self . uuid (), // 👈 Don't use 'UUID()'
114
+ id : uuid (), // 👈 Don't use 'UUID()'
107
115
name : " " ,
108
- createdAt : self . now // 👈 Don't use 'Date()'
116
+ createdAt : now // 👈 Don't use 'Date()'
109
117
)
110
118
)
111
119
}
@@ -120,23 +128,22 @@ inside the `addButtonTapped` method, you can use the [`withDependencies`][withde
120
128
function to override any dependencies for the scope of one single test. It's as easy as 1-2-3:
121
129
122
130
``` swift
123
- func testAdd () async throws {
124
- let model = withDependencies {
131
+ @Test
132
+ func add () async throws {
133
+ withDependencies {
125
134
// 1️⃣ Override any dependencies that your feature uses.
126
- $0 .clock = ImmediateClock ()
135
+ $0 .clock = . immediate
127
136
$0 .date .now = Date (timeIntervalSinceReferenceDate : 1234567890 )
128
137
$0 .uuid = .incrementing
129
138
} operation : {
130
139
// 2️⃣ Construct the feature's model
131
140
FeatureModel ()
132
141
}
133
-
134
142
// 3️⃣ The model now executes in a controlled environment of dependencies,
135
143
// and so we can make assertions against its behavior.
136
144
try await model.addButtonTapped ()
137
- XCTAssertEqual (
138
- model.items ,
139
- [
145
+ #expect (
146
+ model.items == [
140
147
Item (
141
148
id : UUID (uuidString : " 00000000-0000-0000-0000-000000000000" )! ,
142
149
name : " " ,
@@ -158,19 +165,17 @@ But, controllable dependencies aren't only useful for tests. They can also be us
158
165
previews. Suppose the feature above makes use of a clock to sleep for an amount of time before
159
166
something happens in the view. If you don't want to literally wait for time to pass in order to see
160
167
how the view changes, you can override the clock dependency to be an "immediate" clock using the
161
- [ ` withDependencies ` ] [ withdependencies-docs ] helper :
168
+ ` .dependencies ` preview trait :
162
169
163
170
``` swift
164
- struct Feature_Previews : PreviewProvider {
165
- static var previews: some View {
166
- FeatureView (
167
- model : withDependencies {
168
- $0 .clock = ImmediateClock ()
169
- } operation : {
170
- FeatureModel ()
171
- }
172
- )
171
+ #Preview (
172
+ traits : .dependencies {
173
+ $0 .continuousClock = .immediate
173
174
}
175
+ ) {
176
+ // All access of '@Dependency(\.continuousClock)' in this preview will
177
+ // use an immediate clock.
178
+ FeatureView (model : FeatureModel ())
174
179
}
175
180
```
176
181
0 commit comments