Composição e Teste de Funcionalidades
Combine redutores e teste exaustivamente.
Composição e Teste de Funcionalidades é uma aula grátis de Swift Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Swift Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Swift Academy inclui 4 aulas no total.
Composição de funcionalidades
Aplicativos reais são construídos a partir de muitas funcionalidades pequenas. O TCA permite que uma funcionalidade pai incorpore funcionalidades filhas para que cada uma permaneça focada e, em seguida, as combine em um todo maior. As ferramentas para isso são Scope e a incorporação do state e das ações filhas.
É a composição que dá à Arquitetura Componível seu nome.
import ComposableArchitecture
// A parent feature embeds child State and Action,
// then uses Scope to run the child's reducer.Incorporando o state da funcionalidade filha
O State da funcionalidade pai contém o state da filha como uma propriedade. A enumeração Action da funcionalidade pai tem um caso que encapsula as ações da filha. Esse aninhamento reflete a forma como a interface se aninha.
Aqui, uma funcionalidade pai contém uma filha counter.
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() }
}Definindo o escopo da filha
Scope executa o redutor filho na parte do state e da ação pai que lhe pertence. Você fornece um caminho de chave de state e um caminho de caso de ação e, em seguida, o redutor filho.
Isso integra a filha ao ciclo de update do pai.
import ComposableArchitecture
var body: some ReducerOf<Self> {
Scope(state: \.counter, action: \.counter) {
CounterFeature()
}
Reduce { state, action in
// parent-specific logic here
return .none
}
}Combinando vários redutores
O body de uma funcionalidade pode listar vários redutores; o TCA os executa em ordem para cada ação. Isso permite colocar um ou mais Scopes ao lado do próprio Reduce da funcionalidade pai.
Aqui, duas filhas e a lógica do pai coexistem.
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
}
}Configurando o store para visualizações filhas
No lado da visualização, uma visualização filha precisa de um store especializado para a filha. A visualização pai o deriva com store.scope, mapeando para o state e a ação da filha.
Aqui, a visualização pai passa um store com scope para a visualização counter.
import ComposableArchitecture
import SwiftUI
struct AppView: View {
let store: StoreOf<AppFeature>
var body: some View {
CounterView(
store: store.scope(state: \.counter, action: \.counter)
)
}
}Apresentando o TestStore
O TestStore permite verificar exatamente como uma funcionalidade se comporta. Você envia ações e descreve como o state deve mudar; se a realidade for diferente, o teste falha. Essa verificação exaustiva detecta regressões sutis.
Você o cria como um store normal, com o state inicial e o redutor.
import ComposableArchitecture
import XCTest
func testIncrement() async {
let store = await TestStore(initialState: CounterFeature.State()) {
CounterFeature()
}
}Verificando alterações de state
Quando você envia uma ação para um TestStore, passa um fechamento que descreve a mutação esperada. O teste é aprovado somente se o state mudar exatamente dessa forma.
Aqui, incrementar deve elevar a contagem de 0 para 1.
import ComposableArchitecture
import XCTest
func testIncrement() async {
let store = await TestStore(initialState: CounterFeature.State()) {
CounterFeature()
}
await store.send(.incrementTapped) {
$0.count = 1
}
}Exaustividade
Por padrão, um TestStore é exaustivo: você precisa considerar cada alteração de state e cada ação que um efeito devolve. Alterações não tratadas fazem o teste falhar, mantendo suas afirmações honestas.
Você pode flexibilizar isso com store.exhaustivity = .off para testes focados.
import ComposableArchitecture
// Exhaustive (default): every change must be asserted.
// Relax when you only care about part of the behavior:
store.exhaustivity = .offRecebendo ações de efeitos
Quando um efeito envia uma ação de volta, o teste precisa usar receive para recebê-la e verificar o state resultante. Isso comprova que o fluxo assíncrono funciona de ponta a ponta.
Aqui, um recarregamento dispara uma resposta que o teste aguarda e verifica.
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
}
}Substituindo dependências nos testes
Para tornar os efeitos determinísticos, substitua as dependências ao construir o TestStore. Forneça um cliente falso ou um relógio de teste para que os resultados sejam previsíveis.
Aqui, o cliente numérico é substituído por um que sempre retorna 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 }
}Testando funcionalidades compostas
Como a composição aninha state e ações, você testa uma funcionalidade pai enviando ações da filha encapsuladas no caso do pai. As mesmas afirmações exaustivas se aplicam, verificando toda a árvore.
Aqui, um pai recebe um incremento de counter por meio de seu scope.
import ComposableArchitecture
import XCTest
func testChildInParent() async {
let store = await TestStore(initialState: AppFeature.State()) {
AppFeature()
}
await store.send(.counter(.incrementTapped)) {
$0.counter.count = 1
}
}Verificação rápida: comportamento do TestStore
Relembre o que um TestStore padrão exige de suas afirmações.
Recapitulação: composição e testes
Você concluiu o conjunto de ferramentas do TCA:
Scopeexecuta um redutor filho em uma parte do state e da ação pai, e vários redutores podem ser combinados em um únicobody.store.scopefornece a uma visualização filha seu próprio store especializado.TestStoreverifica alterações exatas de state quando você envia ações comsend.- Ele é exaustivo por padrão e usa
receivepara ações orientadas por efeitos. - Substitua as dependências com
withDependenciespara testes determinísticos.
Agora você pode criar, compor e testar rigorosamente funcionalidades com a Arquitetura Componível.
import ComposableArchitecture
// Recap: Scope to compose, TestStore to verify.
// Exhaustive assertions + injected fakes = confidence.Aprenda Swift com um tutor de IA — grátis
Escreva e execute código real no seu navegador, obtenha ajuda instantânea de um tutor de IA 24/7 e continue de onde parou na web ou no app.
- Cursos
- 122
- Aulas
- 409
Perguntas Frequentes
A aula “Composição e Teste de Funcionalidades” é grátis?
Sim — o texto completo de “Composição e Teste de Funcionalidades” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Swift Academy, atualize para CoddyKit PRO. O curso de Swift Academy inclui 4 aulas no total.
O que vou aprender em “Composição e Teste de Funcionalidades”?
Combine redutores e teste exaustivamente. Você pratica Swift Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Swift Academy?
Nenhuma experiência prévia é necessária. Swift Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.
Quanto tempo leva a aula “Composição e Teste de Funcionalidades”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Swift Academy?
Sim. Cada aula de Swift Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Estado, Ação e Redutor
- A Store e a Integração com SwiftUI
- Efeitos e Dependências
- Composição e Teste de Funcionalidades