Composición y pruebas de funcionalidades
Combine reductores y realice pruebas exhaustivas.
Composición y pruebas de funcionalidades es una lección gratuita de Swift Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Swift Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Swift Academy incluye 4 lecciones en total.
Composición de funcionalidades
Las aplicaciones reales se construyen a partir de muchas funcionalidades pequeñas. TCA permite que una funcionalidad principal integre funcionalidades hijas para que cada una se mantenga enfocada y, después, las combine en un conjunto más grande. Las herramientas para ello son Scope y la integración del estado y las acciones de las funcionalidades hijas.
La composición es lo que da nombre a The Composable Architecture.
import ComposableArchitecture
// A parent feature embeds child State and Action,
// then uses Scope to run the child's reducer.Integrar el estado de una hija
El State de la funcionalidad principal contiene el estado de la hija como una propiedad. El enum Action de la funcionalidad principal tiene un caso que envuelve las acciones de la hija. Esta anidación refleja cómo se anida la interfaz.
Aquí, una funcionalidad principal contiene una funcionalidad hija de contador.
import ComposableArchitecture
@Reducer
struct AppFeature {
@ObservableState
struct State: Equatable {
var counter = CounterFeature.State()
}
enum Action {
case counter(CounterFeature.Action)
}
var body: some ReducerOf<Self> { EmptyReducer() }
}Definir el ámbito de la hija
Scope ejecuta el reductor hijo sobre la parte del estado y la acción principales que le corresponden. Se le proporciona una ruta de clave de estado y una ruta de caso de acción, y después el reductor hijo.
Esto conecta la funcionalidad hija con el ciclo de actualización de la principal.
import ComposableArchitecture
var body: some ReducerOf<Self> {
Scope(state: \.counter, action: \.counter) {
CounterFeature()
}
Reduce { state, action in
// parent-specific logic here
return .none
}
}Combinar varios reductores
El body de una funcionalidad puede enumerar varios reductores; TCA los ejecuta en orden para cada acción. Esto permite colocar uno o varios Scope junto al propio Reduce de la funcionalidad principal.
Aquí conviven dos funcionalidades hijas y la lógica principal.
import ComposableArchitecture
var body: some ReducerOf<Self> {
Scope(state: \.profile, action: \.profile) { ProfileFeature() }
Scope(state: \.settings, action: \.settings) { SettingsFeature() }
Reduce { state, action in
return .none
}
}Definir el ámbito del store para las vistas hijas
En la vista, una vista hija necesita un store especializado para ella. La vista principal lo obtiene mediante store.scope, mapeándolo al estado y la acción de la hija.
Aquí, la vista principal pasa un store con ámbito a la vista del contador.
import ComposableArchitecture
import SwiftUI
struct AppView: View {
let store: StoreOf<AppFeature>
var body: some View {
CounterView(
store: store.scope(state: \.counter, action: \.counter)
)
}
}Introducción a TestStore
TestStore le permite comprobar exactamente cómo se comporta una funcionalidad. Envía acciones y describe cómo debe cambiar el estado; si la realidad difiere, la prueba falla. Esta comprobación exhaustiva detecta regresiones sutiles.
Se crea como un store normal, con el estado inicial y el reductor.
import ComposableArchitecture
import XCTest
func testIncrement() async {
let store = await TestStore(initialState: CounterFeature.State()) {
CounterFeature()
}
}Comprobar cambios de estado
Al enviar una acción a un TestStore, se proporciona un cierre que describe la mutación esperada. La prueba solo pasa si el estado cambia exactamente de esa manera.
Aquí, incrementar debe aumentar el valor de count de 0 a 1.
import ComposableArchitecture
import XCTest
func testIncrement() async {
let store = await TestStore(initialState: CounterFeature.State()) {
CounterFeature()
}
await store.send(.incrementTapped) {
$0.count = 1
}
}Exhaustividad
Por defecto, un TestStore es exhaustivo: debe tener en cuenta cada cambio de estado y cada acción que un efecto devuelva. Las modificaciones no gestionadas hacen fallar la prueba, lo que mantiene sus comprobaciones rigurosas.
Puede relajar este comportamiento con store.exhaustivity = .off para pruebas específicas.
import ComposableArchitecture
// Exhaustive (default): every change must be asserted.
// Relax when you only care about part of the behavior:
store.exhaustivity = .offRecibir acciones de efectos
Cuando un efecto devuelve una acción, la prueba debe recibirla con receive y comprobar el estado resultante. Esto demuestra que el flujo asíncrono funciona de principio a fin.
Aquí, una recarga desencadena una respuesta que la prueba espera y comprueba.
import ComposableArchitecture
import XCTest
func testReload() async {
let store = await TestStore(initialState: NumberFeature.State()) {
NumberFeature()
}
await store.send(.reload)
await store.receive(\.response) {
$0.value = 42
}
}Anular dependencias en las pruebas
Para que los efectos sean deterministas, anule las dependencias al construir el TestStore. Proporcione un cliente simulado o un reloj de prueba para que los resultados sean predecibles.
Aquí, el cliente de números se sustituye por uno que siempre devuelve 42.
import ComposableArchitecture
import XCTest
func testReload() async {
let store = await TestStore(initialState: NumberFeature.State()) {
NumberFeature()
} withDependencies: {
$0.numberClient.fetch = { 42 }
}
await store.send(.reload)
await store.receive(\.response) { $0.value = 42 }
}Probar funcionalidades compuestas
Como la composición anida el estado y las acciones, se prueba una funcionalidad principal enviando acciones de la hija envueltas en el caso de la principal. Se aplican las mismas comprobaciones exhaustivas para verificar todo el árbol.
Aquí, la funcionalidad principal recibe un incremento del contador a través de su ámbito.
import ComposableArchitecture
import XCTest
func testChildInParent() async {
let store = await TestStore(initialState: AppFeature.State()) {
AppFeature()
}
await store.send(.counter(.incrementTapped)) {
$0.counter.count = 1
}
}Comprobación rápida: comportamiento de TestStore
Recuerde qué exige un TestStore predeterminado a sus comprobaciones.
Resumen: composición y pruebas
Ha completado el conjunto de herramientas de TCA:
Scopeejecuta un reductor hijo sobre una parte del estado y la acción principales, y se pueden combinar varios reductores en un mismobody.store.scopeproporciona a una vista hija su propio store especializado.TestStorecomprueba los cambios exactos de estado cuando se envían acciones consend.- Es exhaustivo por defecto y utiliza
receivepara las acciones impulsadas por efectos. - Anule las dependencias con
withDependenciespara realizar pruebas deterministas.
Ahora puede crear, componer y probar rigurosamente funcionalidades con The Composable Architecture.
import ComposableArchitecture
// Recap: Scope to compose, TestStore to verify.
// Exhaustive assertions + injected fakes = confidence.Aprende Swift con un tutor de IA — gratis
Escribe y ejecuta código real en tu navegador, obtén ayuda instantánea de un tutor de IA disponible 24/7 y continúa donde lo dejaste en la web o en la aplicación.
- Cursos
- 122
- Lecciones
- 409
Preguntas frecuentes
¿La lección «Composición y pruebas de funcionalidades» es gratis?
Sí — el texto completo de «Composición y pruebas de funcionalidades» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Swift Academy, actualiza a CoddyKit PRO. El curso de Swift Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Composición y pruebas de funcionalidades»?
Combine reductores y realice pruebas exhaustivas. Practicas Swift Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Swift Academy?
No se requiere experiencia previa. Swift Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.
¿Cuánto tiempo toma la lección «Composición y pruebas de funcionalidades»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Swift Academy?
Sí. Cada lección de Swift Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Estado, acción y reductor
- El Store e integración con SwiftUI
- Efectos y dependencias
- Composición y pruebas de funcionalidades