Testando Seus Handlers
Um TaskHandler/AnswerProvider/DueDateProvider é uma classe Java comum — na maioria dos casos,
ele não precisa do motor rodando para ser testado. Reserve testes com o motor real para verificar o
fluxo do processo (roteamento, variáveis se propagando entre nós), não a lógica interna de cada
handler.
Caminho recomendado: teste unitário isolado
Mocke ExecutionContext e teste o handler como testaria qualquer outra classe:
@Test
void lancaErroDeNegocioQuandoCpfInvalido() {
ExecutionContext execution = mock(ExecutionContext.class);
when(execution.getVariable("cpf"))
.thenReturn(new ProcessVariable("cpf", "cpf-invalido"));
CalcularScoreTaskHandler handler = new CalcularScoreTaskHandler(mock(BureauClient.class));
assertThrows(ProcessErrorException.class, () -> handler.handle(execution));
}
Sem Spring, sem motor, sem I/O — roda em milissegundos e é o lugar certo para cobrir as ramificações de lógica de negócio do handler (casos de borda, validações, cálculos — a fórmula do score, aqui).
Teste de integração: o fluxo completo com o motor real
Quando você quer verificar que um processo inteiro se comporta como esperado — o roteamento de um
gateway, a propagação de variáveis entre nós, o efeito de completar uma tarefa externa — suba um
@SpringBootTest real trocando a persistência de produção pela implementação in-memory:
<dependency>
<groupId>io.kikwiflow</groupId>
<artifactId>kikwi-in-memory-spring-boot-starter</artifactId>
<version>${kikwiflow.version}</version>
<scope>test</scope>
</dependency>
@SpringBootTest
class AberturaDeContaProcessoIT {
@Autowired
private KikwiflowEngine kikwiflowEngine;
@Test
void concluiAposAnalistaAprovar() {
ProcessInstance instancia = kikwiflowEngine.startProcess()
.byKey("abertura-de-conta")
.withBusinessKey("111.111.111-11")
.withVariables(Map.of(
"cpf", new ProcessVariable("cpf", "111.111.111-11"),
"rendaDeclarada", new ProcessVariable("rendaDeclarada", 8000)))
.execute();
// Calcular Score é síncrona; a instância já está parada em "Aprovar Abertura".
assertEquals(ProcessInstanceStatus.ACTIVE, instancia.status());
kikwiflowEngine.completeExternalTask(
findPendingTaskId(instancia, "Aprovar Abertura"),
Map.of("decisao", new ProcessVariable("decisao", "APROVADA")),
IdentityContext.system());
ProcessInstance concluida = kikwiflowEngine.findProcessInstanceById(instancia.id());
assertEquals(ProcessInstanceStatus.COMPLETED, concluida.status());
}
}
kikwi-in-memory-spring-boot-starter registra um KikwiEngineRepository in-memory automaticamente
(via @ConditionalOnMissingBean), então basta ele estar no classpath de teste — nenhuma
configuração adicional é necessária, e nenhum Mongo real é necessário para este teste.
commitBefore: true) exigem esperar o pollerDiferente do caminho totalmente síncrono do exemplo acima, um nó com commitBefore: true é retomado
por um worker interno que faz polling periódico
(kikwiflow.execution.task-acquisition-interval-millis, default 5 segundos) — em um @SpringBootTest
real esse poller está de fato rodando, então o teste precisa esperar (por exemplo, com Awaitility)
até a instância alcançar o status esperado, em vez de assumir que o resultado já está pronto assim
que .execute() retorna. É o caso do ramo Consulta Bureau de
Processamento Paralelo.
Assertions mais expressivas (opcional)
Se quiser um vocabulário de asserção mais rico do que inspecionar ProcessInstance na mão
(assertThatProcessInstanceIsActive, assertHasActiveExternalTaskOn, etc.), adicione
kikwi-core-testing como dependência de teste e substitua o bean de repositório pela sua
AssertableKikwiEngine:
<dependency>
<groupId>io.kikwiflow</groupId>
<artifactId>kikwi-core-testing</artifactId>
<version>${kikwiflow.version}</version>
<scope>test</scope>
</dependency>
@TestConfiguration
class AssertableEngineTestConfig {
@Bean
@Primary
KikwiEngineRepository assertableKikwiEngine() {
return new AssertableKikwiEngine();
}
}
@SpringBootTest
@Import(AssertableEngineTestConfig.class)
class AberturaDeContaAssertableIT {
@Autowired
private KikwiflowEngine kikwiflowEngine;
@Autowired
private AssertableKikwiEngine assertableKikwiEngine;
@Test
void paraEmAprovarAberturaAposCalcularScore() {
kikwiflowEngine.startProcess()
.byKey("abertura-de-conta")
.withBusinessKey("BK-TEST-2")
.withVariables(Map.of(
"cpf", new ProcessVariable("cpf", "222.222.222-22"),
"rendaDeclarada", new ProcessVariable("rendaDeclarada", 9000)))
.execute();
assertableKikwiEngine.assertHasActiveExternalTaskOn("Aprovar Abertura");
}
}
AssertableKikwiEngine implementa KikwiEngineRepository diretamente — como Spring escolhe o bean
marcado @Primary, o resto da fiação (KikwiflowEngine, Navigator, ContinuationService) passa
a operar sobre ele sem qualquer outra mudança de configuração.
Não existe (ainda) um @KikwiflowTest/test slice do Spring Boot que faça essa troca de bean
automaticamente — o @TestConfiguration acima é curto, mas é algo que você mesmo declara no seu
projeto.
Quando usar / quando não usar
Use teste unitário para toda regra de negócio dentro de um handler — é rápido, e é onde os casos de borda cabem.
Use teste de integração com o motor para verificar o fluxo: um gateway roteando para o lado certo, uma variável chegando no nó seguinte, uma tarefa externa liberando a continuação. Não o use para reexercitar a lógica que o teste unitário já cobre.
Próximo passo
Com os handlers testados, o processo básico está completo. A partir daqui a trilha entra em tópicos avançados — o primeiro é rodar passos independentes ao mesmo tempo, em Processamento Paralelo.