A forma como você testa unidades ou módulos que se comunicam com fluxos depende se o objeto em teste usa o fluxo como entrada ou saída.
- Se o objeto em teste observa um fluxo, é possível gerar fluxos em dependências fictícias que você pode controlar pelos testes.
- Se a unidade ou o módulo expõe um fluxo, é possível ler e verificar um ou vários itens emitidos por um fluxo no teste.
Como criar um produtor fictício
Quando o objeto em teste é um consumidor de um fluxo, uma maneira comum de testá-lo é substituir o produtor por uma implementação fictícia. Por exemplo, considerando uma classe que observa um repositório que usa dados de duas fontes de dados na produção:

Para que o teste seja determinista, substitua o repositório e as dependências dele por um repositório fictício que sempre emite os mesmos dados fictícios:

Para emitir uma série predefinida de valores em um fluxo, use o builder flow
:
class MyFakeRepository : MyRepository {
fun observeCount() = flow {
emit(ITEM_1)
}
}
No teste, esse repositório fictício é injetado, substituindo a implementação real:
@Test
fun myTest() {
// Given a class with fake dependencies:
val sut = MyUnitUnderTest(MyFakeRepository())
// Trigger and verify
...
}
Agora que você tem controle sobre as saídas do objeto em teste, é possível verificar se ele funciona corretamente conferindo a saída dele.
Como declarar emissões de fluxo em um teste
Se o objeto em teste estiver expondo um fluxo, ele precisará fazer declarações sobre os elementos do fluxo de dados.
Vamos supor que o repositório do exemplo anterior exponha um fluxo:

Dependendo das necessidades do teste, você normalmente verificará a primeira emissão ou um número finito de itens provenientes do fluxo.
Você pode consumir a primeira emissão para o fluxo chamando first()
. Essa
função aguarda até que o primeiro item seja recebido e, em seguida, envia o
sinal de cancelamento ao produtor.
@Test
fun myRepositoryTest() = runBlocking {
// Given a repository that combines values from two data sources:
val repository = MyRepository(fakeSource1, fakeSource2)
// When the repository emits a value
val firstItem = repository.counter.first() // Returns the first item in the flow
// Then check it's the expected item
assertThat(firstItem, isEqualTo(ITEM_1) // Using AssertJ
}
Se o teste precisar verificar vários valores, chamar toList()
fará com que o
fluxo aguarde a fonte emitir todos os valores e, em seguida, retornará esses
valores como uma lista. Isso funciona apenas para fluxos de dados finitos.
@Test
fun myRepositoryTest() = runBlocking {
// Given a repository with a fake data source that emits ALL_MESSAGES
val messages = repository.observeChatMessages().toList()
// When all messages are emitted then they should be ALL_MESSAGES
assertThat(messages, isEqualTo(ALL_MESSAGES))
}
Para fluxos de dados que exigem uma coleção mais complexa de itens ou
que não retornam um número finito de itens, você pode usar a API Flow
para selecionar e transformar os itens. Veja alguns exemplos:
// Take the second item
outputFlow.drop(1).first()
// Take the first 5 items
outputFlow.take(5).toList()
// Take the first 5 distinct items
outputFlow.take(5).toSet()
// Take the first 2 items matching a predicate
outputFlow.takeWhile(predicate).take(2).toList()
// Take the first item that matches the predicate
outputFlow.firstWhile(predicate)
// Take 5 items and apply a transformation to each
outputFlow.map(transformation).take(5)
// Takes the first item verifying that the flow is closed after that
outputFlow.single()
// Finite data streams
// Verify that the flow emits exactly N elements (optional predicate)
outputFlow.count()
outputFlow.count(predicate)
CoroutineDispatcher como dependência
Se o objeto em teste tiver um CoroutineDispatcher
como dependência,
transmita uma instância do
TestCoroutineDispatcher
para a
biblioteca kotlinx-coroutines-test
e execute o corpo do teste no método runBlockingTest
do
agente:
private val coroutineDispatcher = TestCoroutineDispatcher()
private val uut = MyUnitUnderTest(coroutineDispatcher)
@Test
fun myTest() = coroutineDispatcher.runBlockingTest {
// Test body
}