Professional Documents
Culture Documents
Chapter 5 - Building The Domain of An Android Application - Clean Android Architecture
Chapter 5 - Building The Domain of An Android Application - Clean Android Architecture
Requerimentos técnicos
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 1/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
Apresentando a arquitetura do
aplicativo
Nesta seção, nósdiscutirá a arquitetura mais comum que pode ser aplicada a
um aplicativo Android e como ela pode ser combinadacom princípios de ar-
quitetura limpa e veja como devemos estruturar idealmente nossa base de
código.
Nos exercícios dos capítulos anteriores, vimos como, para uma aplicação que
requer a integração de várias fontes de dados para rede e persistência, tive-
mos que colocar muita lógica dentro da classe ViewModel . Nesses exemplos, o
ViewModel tinha várias responsabilidades, incluindo buscar os dados da Inter-
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 2/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 3/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
Para separar as camadas,pode usar módulos Android . Isso nos ajudará a im-
por mais rigor ao projeto, evitando dependências indesejadas entre as cama-
das. Isso também ajuda a melhorar os tempos de compilação em aplicativos
grandes devido ao cache de compilação do Gradle, que apenas reconstruirá os
módulos que tiveram alterações no código. Isso será algo como a figura a
seguir:
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 4/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
pandir a camada de apresentação por causa de como certas telas são agrupa-
das para formar certos recursos e fluxos isolados dentro de um aplicativo
(como uma seção de configurações do aplicativo ou um fluxo de
login/inscrição). Um aspecto interessante a ser observado é o :appmódulo, que
tem a função de combinar todas as dependências e montá-las. Aqui, vamos
reunir todas as dependências necessárias e inicializá-las.
Uma coisa importante a notar aqui é que os módulos não são equivalentes às
próprias camadas; módulos de dados podem ter dependências para módulos
de dados de nível inferior. De fato, essa situação ocorrerá em cenários em que
um módulo de uma camada precisará ter uma dependência de outro módulo
da mesma camada. Se fôssemos criar uma dependênciaentre os dois, podemos
acabar com uma dependência cíclica, o que não é desejado. Nessa situação,
precisaremos criar um módulo comum entre os dois que conterá as dependên-
cias necessárias. Por exemplo, se quisermos navegar de uma tela em
:presentation1 para uma tela em :presentation2 ou qualquer uma das outras,
Para criar um novo módulo do Android Studio, você precisa clicar com o bo-
tão direito do mouse no projeto no Android Studio, selecionar New e depois
Module , conforme mostrado na figura a seguir:
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 5/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
plug-ins {
id 'com.android.library'
…
}
Se quisermos adicionar uma dependência ao módulo recém-criado, podemos
usar o seguinte no módulo app :
dependências {
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 6/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
implementação(projeto(caminho: ":meu-novo-módulo"))
…
}
A sintaxe para adicionar uma dependência a um módulo é semelhante à sin-
taxe para adicionar uma dependência externa e é através do método de imple‐
mentação Gradle . O resto indica que o módulo do aplicativo irádependem de
As entidades são representadas por objetos que contêm dados e são principal-
mente imutáveis. Vamos supor que queremos representar um usuário como
uma entidade. Podemos terminar com algo como o seguinte:
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 7/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
}
Aqui, usamos uma classe de dados simples e declaramos todos os nossos cam-
pos imutáveis com a palavra-chave val . Também temos uma função de lógica
de negócios para este objeto, que retornará o nome completo do usuário.
Em seguida, precisamos definir nossos casos de uso. Como os casos de uso pre-
cisarão obter dados da camada de dados, primeiro precisaremos criar uma
abstração para nosso repositório e terminaremos coma seguir:
interface UserRepository {
fun getUser(id: String): Usuário
}
Aqui, temos apenas um método simples que retornará um usuário baseado em
id . Agora podemos criar um caso de uso para recuperar o usuário:
interface LocalizaçãoRepositório {
fun getLocation(userId: String): Localização
}
Aqui, novamente temos uma abstração de um repositório com um método
para obter um local específico baseado em userId . Se quisermos obter um
usuário e um local associado, precisaremos criar um caso de uso específico
para isso:
class GetUserWithLocationUseCase(
valor privado userRepository: UserRepository,
valor privado locationRepository: LocationRepository
) {
divertido getUser(id: String) =
UserWithLocation(userRepository.getUser(id),
locationRepository.getLocation(id))
}
classe de dados UserWithLocation(
val usuário: usuário,
localização do valor: Localização
)
No exemplo anterior, criamos uma nova entidade chamada UserWithLocation ,
que armazenará User e Location . UserWithLocation será usado como resultado
para o método getUser em GetUserWithLocationUseCase . Isso dependerá de
UserRepository e LocationRepository para buscar os dados relevantes.
interface UserRepository {
fun getUser(id: String): Flow<User>
}
interface LocalizaçãoRepositório {
fun getLocation(id: String): Flow<Location>
}
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 9/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
Aqui, alteramos os tipos de retorno dos métodos para um fluxo Kotlin, que
pode emitir um fluxo de dados ou um único item. Agora, podemos combinar
os diferentes fluxos no fluxo no caso de uso:
class GetUserWithLocationUseCase(
valor privado userRepository: UserRepository,
valor privado locationRepository: LocationRepository
) {
fun getUser(id: String) = combine(
userRepository.getUser(id),
locationRepository.getLocation(id)
) { usuário, local ->
UserWithLocation(usuário, localização)
}.flowOn(Dispatchers.IO)
}
Aqui nóscombine os fluxos User e Location em um fluxo UserWithLocation e
executaremos a busca de dados no dispatcher de IO .
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 10/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
UseCaseException {
return if (lançável é UseCaseException)
throwable else UnknownException(lançável)
}
}
}
Aqui, temoscriou uma classe selada que terá como subclasses um erro dedi-
cado para cada entidade, além de um erro desconhecido que lidará com erros
que não consideramos e um método complementar que verificará um objeto
Throwable e retornará UnknownException para qualquer Throwable que seja 't
de fluxo, mas primeiro podemos combinar a entidade para sucesso com a enti-
dade para erro para garantir que o consumidor do caso de uso não precise ve-
rificar o tipo de Throwable novamente e fazer um elenco. Podemos fazer isso
com a seguinte abordagem:
Error pode ser expandida ainda mais, se necessário, para manter os dados,
class GetUserWithLocationUseCase(
valor privado userRepository: UserRepository,
valor privado locationRepository: LocationRepository
) {
fun getUser(id: String) = combine(
userRepository.getUser(id),
locationRepository.getLocation(id)
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 11/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
Como essas operações se repetirão para vários casos de uso, podemos usar a
abstração para criar um modelo de como cada caso de uso se comporta e dei-
xar as implementações lidarem apenas com o processamento do
necessário.dados. Um exemplo pode ter a seguinte aparência:
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 12/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
class GetUserWithLocationUseCase(
despachante: CoroutineDispatcher,
valor privado userRepository: UserRepository,
valor privado locationRepository: LocationRepository
): UseCase<String, UserWithLocation>(dispatcher) {
substituir fun executeData(input: String):
Fluxo<UserWithLocation> {
retornar combinar(
userRepository.getUser(entrada),
locationRepository.getLocation(input)
) { usuário, local ->
UserWithLocation(usuário, localização)
}
}
}
NissoPor exemplo, GetUserWithLocationUseCase só terá que lidar com o retorno
dos dados necessários relevantes para o caso de uso no método executeData .
Podemos usar genéricos para vincular os tipos de dados que queremos que o
caso de uso processe, introduzindo outras abstrações para a entrada e saída
necessárias:
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 13/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
class GetUserWithLocationUseCase(
despachante: CoroutineDispatcher,
valor privado userRepository: UserRepository,
valor privado locationRepository: LocationRepository
): UseCase< GetUserWithLocationUseCase.Request,
GetUserWithLocationUseCase.Response >(despachante) {
substituir fun executeData(input: Request ): Flow
< Resposta > {
retornar combinar(
userRepository.getUser(input.userId),
locationRepository.getLocation(input.userId)
) { usuário, local ->
Resposta (UserWithLocation(usuário, local))
}
}
classe de dados Request(val userId: String): UseCase.
Solicitar
classe de dados Response(val userWithLocation:
UserWithLocation): UseCase.Response
}
Aqui, fornecemos as implementações para as classes Request e Response e as
usamos ao estender a partir da classe base. Nesse caso, as classes Request e
Responserepresentar objetos de transporte de dados . Quando criamos tem-
plates para casos de uso, é importante observar sua evolução, pois conforme a
complexidade aumenta, o template pode se tornar inadequado.
class GetUserUseCase(
despachante: CoroutineDispatcher,
valor privado userRepository: UserRepository
): UseCase<GetUserUseCase.Request,
GetUserUseCase.Response>(despachante) {
substituir fun executeData(input: Request): Flow
<Resposta> {
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 14/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
return userRepository.getUser(input.userId)
.map {
Resposta(isso)
}
}
classe de dados Request(val userId: String): UseCase.
Solicitar
data class Response(val user: User): UseCase.Response
}
class GetLocationUseCase(
despachante: CoroutineDispatcher,
valor privado locationRepository: LocationRepository
): UseCase<GetLocationUseCase.Request,
GetLocationUseCase.Response>(expedidor) {
substituir fun executeData(input: Request): Flow
<Resposta> {
return
locationRepository.getLocation(input.userId)
.map {
Resposta(isso)
}
}
classe de dados Request(val userId: String): UseCase
.Solicitar
data class Response(val location: Location) :
UseCase.
Resposta
}
Nos exemplos anteriores, temos duas classes para cada caso de uso para recu-
perar um usuário e um local.
class GetUserWithLocationUseCase(
despachante: CoroutineDispatcher,
valor privado getUserUseCase: GetUserUseCase ,
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 15/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
Nissoseção, vimos como construir uma camada de domínio com entidades, ca-
sos de uso e abstrações para repositórios. Na seção a seguir, veremos um exer-
cício relacionado à construção de uma camada de domínio.
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 16/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
um corpo.
Interação : Isso conterá o número total de interações com o aplicativo.
carregados.
defaultMinSdkVersion = 21
…
}
3. No mesmo arquivo, adicione as versões das bibliotecas que serão utilizadas
pelos módulos Gradle:
script de construção {
extensão {
…
versões = [
androidGradlePlugin: "7.0.4",
kotlin: "1.5.31",
punho: "2.40.5",
coreKtx : "1.7.0",
appCompat: "1.4.1",
compor: "1.0.5",
lifecycleRuntimeKtx: "2.4.0",
activityCompose: "1.4.0",
material: "1.5.0",
corrotinas: "1.5.2",
junit : "4.13.2",
mockito : "4.0.0",
expressoJunit : "1.1.3",
espressoCore : "3.4.0"
]
…
}
4. No mesmoarquivo, adicione um mapeamento para as dependências do plu-
gin que todo o projeto usará:
script de construção {
extensão {
…
gradlePlugins = [
android: "com.android.tools.build:
gradle:${versions.
androidGradlePlugin}",
kotlin:
"org.jetbrains.kotlin:kotlin-
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 18/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
gradle-plugin:${versions.kotlin}",
hilt : "com.google.dagger:hilt-
plug-in android-gradle:
${versions.hilt}"
]
…
}
5. A seguir, você vaiprecisa adicionar as dependências às bibliotecas androidx
:
script de construção {
extensão {
…
androidx = [
core : "androidx.core:core-
ktx:${versions.coreKtx}",
appCompat :
"androidx.appcompat:appcompat:${versions.appCompat}",
composeUi :
"androidx.compose.ui:ui:${versions.compose}",
composeMaterial :
"androidx.compose.material:material:${versions.compose
}",
composeUiToolingPreview:
"androidx.compose.ui:ui-tooling-
preview:${versions.compose}",
lifecycleRuntimeKtx :
"androidx.lifecycle:lifecycle-runtime-
ktx:${versions.lifecycleRuntimeKtx}",
composeActivity :
"androidx.activity:activity-
compose:${versions.activityCompose}"
]
…
}
6. A seguir, adicione obibliotecas restantes para design de material, injeção
de dependência e testes:
script de construção {
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 19/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
extensão {
…
matéria = [
material: "com.google.android.
material: material: $
{versions.material}"
]
corrotinas = [
coroutinesAndroid: "org.jetbrains.
kotlinx:kotlinx-coroutines-
android:${versions.coroutines}"
]
di = [
hiltAndroid : "com.google.dagger:hilt-
android:${versions.hilt}",
hiltCompiler: "com.google.dagger:hilt-
compilador:${versions.hilt}"
]
teste = [
junho:
"junit:junit:${versions.junit}",
corrotinas: "org.jetbrains.kotlinx:
kotlinx-coroutines-test:
${versions.coroutines}",
mockito : "org.mockito.kotlin:
mockito-kotlin:${versions.mockito}"
]
teste android = [
junit: "androidx.test.ext
:junit:${versions.espressoJunit}",
espressoCore : "androidx.test.
espresso:espresso-core:$
{versions.espressoCore}",
composeUiTestJunit: "androidx.compose.
ui:ui-test-junit4:${versions.compose}"
]
}
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 20/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
…
}
7. No mesmo arquivo, você precisará substituir os mapeamentos anteriores
como dependências de plugins:
script de construção {
…
dependências {
classpath gradlePlugins.android
classpath gradlePlugins.kotlin
classpath gradlePlugins.hilt
}
}
8. Agora, você precisa alternar para o arquivo build.gradle no módulo do
aplicativo e alterar oconfigurações existentes com as definidas no
build.gradle de nível superior :
andróide {
compileSdk defaultCompileSdkVersion
configuração padrão {
…
minSdk defaultMinSdkVersion
targetSdk defaultTargetSdkVersion
versãoCódigo 1
versionName "1.0"
…
}
…
opções de compilação {
sourceCompileVersion javaCompileVersion
targetCompatibility javaCompileVersion
}
kotlinOptions {
jvmTarget = jvmTarget
useIR = verdadeiro
}
construirRecursos {
compor verdadeiro
}
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 21/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
composeOptions {
kotlinCompilerExtensionVersion
versões.compor
}
…
}
9. No mesmo, você precisará substituir as dependências pelas definidas no ar-
quivo build.gradle de nível superior :
dependências {
implementação androidx.core
implementação androidx.appCompat
material de implementação.material
implementação androidx.composeUi
implementação androidx.composeMaterial
implementação androidx.composeUiToolingPreview
implementação androidx.lifecycleRuntimeKtx
implementação androidx.composeActivity
testImplementação test.junit
}
10. No Android Studio, execute o comando Sync Project with Gradle Files e,
em seguida, o comando Make Project para garantir que o projeto seja com-
pilado sem erros.
11. Crie umnovo módulo para o projeto chamado domain , que será um módulo
de biblioteca Android.
12. No arquivo build.gradle do módulo de domínio , certifique-se de ter os se-
guintes plugins:
plug-ins {
id 'com.android.library'
id 'kotlin-android'
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
}
13. No mesmo arquivo, certifique-se de usar as configurações definidas no ar-
quivo build.gradle de nível superior :
andróide {
compileSdk defaultCompileSdkVersion
configuração padrão {
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 22/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
minSdk defaultMinSdkVersion
targetSdk defaultTargetSdkVersion
…
}
…
opções de compilação {
sourceCompileVersion javaCompileVersion
targetCompatibility javaCompileVersion
}
kotlinOptions {
jvmTarget = jvmTarget
}
}
14. No mesmoarquivo, você precisará adicionar as seguintes dependências:
dependências {
implementação coroutines.coroutinesAndroid
implementação di.hiltAndroid
kapt di.hiltCompiler
testImplementação test.junit
testImplementação test.coroutines
testImplementação test.mockito
}
15. Sincronize o projeto com os arquivos Gradle e compile o projeto nova-
mente para garantir que a configuração do Gradle esteja correta.
16. No módulo de domínio , crie um novo pacote chamado entity .
17. No pacote de entidade , crieuma classe chamada Post , que terá id , use‐
rId , title e body :
classe de dados Post(
val id: Longo,
val userId: Longo,
val título: String,
val corpo: String
)
18. No mesmo pacote, crie a classe User , que terá id , name , username e email :
classe de dados Usuário(
val id: Longo,
nome do valor: String,
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 23/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 24/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 25/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
emit(Result.Error(UseCaseException.
createFromThrowable(it)))
}
processo abstrato interno divertido (solicitação:
I): Flow<O>
class Configuration(val dispatcher:
CoroutineDispatcher)
Solicitação de interface
Resposta da interface
}
29. No pacote de casos de uso, crie o caso de uso para recuperar a lista de pos-
tagens com as informações do usuário e os dados de interação:
class GetPostsWithUsersWithInteractionUseCase @Inject
construtor(
configuração: configuração,
valor privado postRepository: PostRepository,
valor privado userRepository: UserRepository,
private val transactionRepository:
InteractionRepository
): GetPostsWithUsersWithInteractionUseCase
GetPostsWithUsersWithInteractionUseCase {
substituir o processo divertido (solicitação:
Solicitação):
Fluxo<Resposta> =
combinar(
postRepository.getPosts(),
userRepository.getUsers(),
interaçãoRepository.getInteraction()
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 26/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
30. Nomesmo pacote, crie o caso de uso para recuperar um post por ID:
class GetPostUseCase @Inject construtor(
configuração: configuração,
valor privado postRepository: PostRepository
): UseCase<GetPostUseCase.Request,
GetPostUseCase.Response>(configuração) {
substituir processo divertido (solicitação:
Solicitação): Fluxo
<Resposta> =
postRepository.getPost(request.postId)
.map {
Resposta(isso)
}
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 27/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 28/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
(solicitação.interação)
.map {
Resposta
}
}
classe de dados Request(val interação: Interação):
UseCase.Request
Resposta do objeto: UseCase.Response
}
33. Para teste de unidadeo código, precisamos criar uma nova pasta chamada
resources na pasta de teste do módulo de domínio .
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 29/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 30/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
38. Por fim, crieum método de teste que verificará o método de processo do
caso de uso que estamos testando:
@ExperimentalCoroutinesApi
@Teste
fun testProcess() = runBlockingTest {
val user1 = User(1L, "nome1", "username1",
"email1")
val user2 = User(2L, "nome2", "username2",
"email2")
val post1 = Post(1L, user1.id, "title1",
"body1")
val post2 = Post(2L, user1.id, "title2",
"body2")
val post3 = Post(3L, user2.id, "title3",
"body3")
val post4 = Post(4L, user2.id, "title4",
"body4")
val interação = Interação(10)
sempre(userRepository.getUsers()).thenReturn
(flowOf(listOf(usuário1, usuário2)))
sempre(postRepository.getPosts()).thenReturn
(flowOf(listOf(post1, post2, post3, post4)))
sempre(interactionRepository.getInteraction
()).thenReturn(flowOf(interação))
val resposta = useCase.process
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 31/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
(GetPostsWithUsersWithInteractionUseCase.
Solicitar).first()
assertEquals(
GetPostsWithUsersWithInteractionUseCase.
Resposta(
lista de(
PostWithUser(post1, user1),
PostWithUser(post2, user1),
PostWithUser(post3, user2),
PostWithUser(post4, user2),
), interação
),
resposta
)
}
Se executarmos os testes para esses dois métodos, eles devem passar. Para tes-
tar os casos de uso restantes, podem ser aplicados os mesmos princípios que
usamos para GetPostsWithUsersWithInteractionUseCaseTest – criar repositó-
rios simulados, injetá-los no objeto que desejamos testar e, em seguida, definir
os simulados para a entrada do método do processo e os resultados que deve-
mos esperar, o que nos dará saída comomostrado na captura de tela a seguir:
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 32/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
Resumo
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 33/34
26/10/2022 21:43 Chapter 5: Building the Domain of an Android Application | Clean Android Architecture
Apoiar Sair
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_05_ePub.xhtml#_idParaDest-71 34/34