Skip to content

Commit

Permalink
Add unit tests for BookmarksRepository and AuthRepository
Browse files Browse the repository at this point in the history
  • Loading branch information
DesarrolloAntonio committed Aug 2, 2024
1 parent 5d97658 commit e3998e4
Show file tree
Hide file tree
Showing 5 changed files with 466 additions and 55 deletions.
2 changes: 2 additions & 0 deletions data/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ dependencies {
testImplementation(libs.mockito.kotlin) // Kotlin extension for Mockito to better support Kotlin features.
testImplementation(libs.kotlin.coroutines.test) // Coroutines Test library for testing Kotlin coroutines.
testImplementation(libs.kotlin.test.junit5) // Kotlin Test library for JUnit 5 support.
testImplementation(libs.androidx.paging.common) // Common Paging library for testing.


// Android Testing libraries
androidTestImplementation ("androidx.test:core:1.5.0") // Core testing library for Android, providing API for test infrastructure.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,77 +1,286 @@
package com.desarrollodroide.data.repository

import com.desarrollodroide.common.result.ErrorHandler
import com.desarrollodroide.data.UserPreferences
import com.desarrollodroide.data.local.preferences.SettingsPreferenceDataSource
import com.desarrollodroide.model.Account
import com.desarrollodroide.model.User
import com.desarrollodroide.network.model.AccountDTO
import com.desarrollodroide.network.model.SessionDTO
import com.desarrollodroide.network.retrofit.RetrofitNetwork
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
import org.mockito.Mockito.doNothing
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.toList
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.mockito.Mockito.*
import retrofit2.Response
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
import org.mockito.kotlin.check
import com.desarrollodroide.common.result.Result
import com.desarrollodroide.network.model.LoginResponseDTO
import com.desarrollodroide.network.model.LoginResponseMessageDTO
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.ResponseBody.Companion.toResponseBody
import org.mockito.kotlin.anyOrNull
import java.io.IOException

class AuthRepositoryTest {
@ExperimentalCoroutinesApi
class AuthRepositoryImplTest {

@Mock
lateinit var apiService: RetrofitNetwork
private lateinit var apiService: RetrofitNetwork

@Mock
lateinit var settingsPreferenceDataSource: SettingsPreferenceDataSource
private lateinit var settingsPreferenceDataSource: SettingsPreferenceDataSource

@Mock
lateinit var errorHandler: ErrorHandler
private lateinit var errorHandler: ErrorHandler

private lateinit var authRepositoryImpl: AuthRepositoryImpl
private lateinit var authRepository: AuthRepositoryImpl

@BeforeEach
fun setUp() {
MockitoAnnotations.initMocks(this)
authRepositoryImpl = AuthRepositoryImpl(apiService, settingsPreferenceDataSource, errorHandler)
fun setup() {
MockitoAnnotations.openMocks(this)
authRepository = AuthRepositoryImpl(apiService, settingsPreferenceDataSource, errorHandler)
}
//
// @Test
// fun `sendLogin saves user on successful login`() = runBlocking {
// val username = "user"
// val password = "pass"
// val serverUrl = "http://test.com"
// val sessionDTO = SessionDTO("sessionId", null, null)
// val userPreferences = UserPreferences.newBuilder()
// .setUsername(username)
// .setOwner(false)
// .setPassword(password)
// .setSession("sessionId")
// .setUrl(serverUrl)
// .setRememberPassword(true)
// .build()
//
// `when`(apiService.sendLogin(anyString(), anyString())).thenReturn(Response.success(sessionDTO))
// doNothing().`when`(settingsPreferenceDataSource).saveUser(any(UserPreferences::class.java), anyString(), anyString())
//
// authRepositoryImpl.sendLogin(username, password, serverUrl).collect { /* Aquí puedes hacer assertions sobre el resultado */ }
//
//// verify(settingsPreferenceDataSource).saveUser(
//// argThat { session == "sessionId" && url == serverUrl && this.password == password },
//// eq(serverUrl),
//// eq(password)
//// )
// }

// @Test
// fun `sendLogout resets user data on successful logout`() = runBlocking {
// val serverUrl = "http://test.com"
// val xSession = "sessionId"
//
// `when`(apiService.sendLogout(anyString(), anyString())).thenReturn(Response.success("Logged out"))
//
// authRepositoryImpl.sendLogout(serverUrl, xSession).collect { /* Here you can assert the result */ }
//
// verify(settingsPreferenceDataSource).resetUser()
// }
}

@Test
fun `sendLogin should emit Loading and Success states when API call is successful`() = runTest {
// Arrange
val username = "testUser"
val password = "testPassword"
val serverUrl = "http://test.com"
val sessionDTO = SessionDTO(
"testSession",
"testToken",
AccountDTO(1, username, isOwner = false, isLegacyApi = true)
)
val expectedUser =
User("testToken", "testSession", Account(1, username, password, false, serverUrl, true))

`when`(apiService.sendLogin(anyString(), any())).thenReturn(Response.success(sessionDTO))
`when`(settingsPreferenceDataSource.getUser()).thenReturn(flowOf(expectedUser))

// Act
val results = authRepository.sendLogin(username, password, serverUrl).toList()

// Assert
assertEquals(3, results.size, "Expected 3 emitted results")
assertTrue(results[0] is Result.Loading && results[0].data == null)
assertTrue(results[1] is Result.Loading && results[1].data != null)
assertTrue(results[2] is Result.Success && results[2].data == expectedUser)

verify(settingsPreferenceDataSource).saveUser(any(), eq(serverUrl), eq(password))
verify(apiService).sendLogin(check { it.endsWith("/api/login") }, any())
}

@Test
fun `sendLogin should emit Loading and Error states when API call fails`() = runTest {
// Arrange
val username = "testUser"
val password = "testPassword"
val serverUrl = "http://test.com"
val errorMessage = "Invalid credentials"
val errorResponseBody = errorMessage.toResponseBody("text/plain".toMediaTypeOrNull())

`when`(apiService.sendLogin(anyString(), any())).thenReturn(Response.error(400, errorResponseBody))
`when`(errorHandler.getApiError(eq(400), anyOrNull(), eq(errorMessage))).thenReturn(Result.ErrorType.HttpError(statusCode = 400, message = errorMessage))
`when`(settingsPreferenceDataSource.getUser()).thenReturn(flowOf()) // Ensure a valid empty flow is returned

// Act
val results = authRepository.sendLogin(username, password, serverUrl).toList()

// Debugging: Print results
results.forEachIndexed { index, result ->
println("Result $index: $result")
if (result is Result.Error) {
println("Result $index error: '${result.error?.message}'")
} else if (result is Result.Loading) {
println("Result $index loading data: '${result.data}'")
}
}

// Assert
assertEquals(3, results.size, "Expected 3 emitted results")
assertTrue(results[0] is Result.Loading && results[0].data == null)
assertTrue(results[1] is Result.Loading && results[1].data == null)
assertTrue(results[2] is Result.Error && (results[2] as Result.Error).error is Result.ErrorType.HttpError)
assertEquals((results[2] as Result.Error).error?.message, errorMessage)

verify(apiService).sendLogin(check { it.endsWith("/api/login") }, any())
}

@Test
fun `sendLogin should emit Loading and Error states when network error occurs`() = runTest {
// Arrange
val username = "testUser"
val password = "testPassword"
val serverUrl = "http://test.com"
val networkErrorMessage = "Network error"
val ioException = IOException(networkErrorMessage)

`when`(apiService.sendLogin(anyString(), any())).thenAnswer { invocation ->
throw ioException
}

`when`(errorHandler.getError(ioException)).thenReturn(Result.ErrorType.IOError(ioException))
`when`(settingsPreferenceDataSource.getUser()).thenReturn(flowOf()) // Ensure a valid empty flow is returned

// Act
val results = authRepository.sendLogin(username, password, serverUrl).toList()

// Assert
assertEquals(3, results.size, "Expected 3 emitted results")
assertTrue(results[0] is Result.Loading && results[0].data == null)
assertTrue(results[1] is Result.Loading && results[1].data == null)
assertTrue(results[2] is Result.Error && (results[2] as Result.Error).error is Result.ErrorType.IOError)
assertEquals(networkErrorMessage, (results[2] as Result.Error).error?.throwable?.message)

verify(apiService).sendLogin(check { it.endsWith("/api/login") }, any())
}

@Test
fun `sendLogin should not call saveUser when API call fails`() = runTest {
// Arrange
val username = "testUser"
val password = "testPassword"
val serverUrl = "http://test.com"
val errorMessage = "Invalid credentials"
val errorResponseBody = errorMessage.toResponseBody("text/plain".toMediaTypeOrNull())

`when`(apiService.sendLogin(anyString(), any())).thenReturn(Response.error(400, errorResponseBody))
`when`(errorHandler.getApiError(eq(400), anyOrNull(), eq(errorMessage))).thenReturn(Result.ErrorType.HttpError(statusCode = 400, message = errorMessage))
`when`(settingsPreferenceDataSource.getUser()).thenReturn(flowOf()) // Ensure a valid empty flow is returned

// Act
val results = authRepository.sendLogin(username, password, serverUrl).toList()

// Assert
assertEquals(3, results.size, "Expected 3 emitted results")
assertTrue(results[0] is Result.Loading && results[0].data == null)
assertTrue(results[1] is Result.Loading && results[1].data == null)
assertTrue(results[2] is Result.Error && (results[2] as Result.Error).error is Result.ErrorType.HttpError)
assertEquals((results[2] as Result.Error).error?.message, errorMessage)

verify(apiService).sendLogin(check { it.endsWith("/api/login") }, any())
verify(settingsPreferenceDataSource, never()).saveUser(any(), anyString(), anyString())
}

@Test
fun `sendLogout should emit Loading, Loading with data, and Success states when API call is successful`() = runTest {
// Arrange
val serverUrl = "http://test.com"
val xSession = "testSession"
val logoutResponse = "Logout successful" // La respuesta esperada del servidor

`when`(apiService.sendLogout(anyString(), anyString())).thenReturn(Response.success(logoutResponse))

// Act
val results = authRepository.sendLogout(serverUrl, xSession).toList()

// Assert
assertEquals(3, results.size, "Expected 3 emitted results")
assertTrue(results[0] is Result.Loading && results[0].data == null, "First result should be Loading with null data")
assertTrue(results[1] is Result.Loading && results[1].data == "", "Second result should be Loading with empty data")
assertTrue(results[2] is Result.Success && (results[2] as Result.Success).data == "") {
"Expected third result to be Success with empty data after resetUser, but was '${(results[2] as Result.Success).data}'"
}

verify(settingsPreferenceDataSource).resetUser()
verify(apiService).sendLogout(check { it.endsWith("/api/logout") }, eq(xSession))
}

@Test
fun `sendLogout should emit Loading and Error states when API call fails`() = runTest {
// Arrange
val serverUrl = "http://test.com"
val xSession = "testSession"
val errorMessage = "Logout failed"
val errorResponseBody = errorMessage.toResponseBody("text/plain".toMediaTypeOrNull())

`when`(apiService.sendLogout(anyString(), anyString())).thenReturn(Response.error(400, errorResponseBody))
`when`(errorHandler.getApiError(eq(400), anyOrNull(), eq(errorMessage))).thenReturn(Result.ErrorType.HttpError(statusCode = 400, message = errorMessage))

// Act
val results = authRepository.sendLogout(serverUrl, xSession).toList()

// Assert
assertEquals(3, results.size, "Expected 3 emitted results")
assertTrue(results[0] is Result.Loading && results[0].data == null, "First result should be Loading with null data")
assertTrue(results[1] is Result.Loading && results[1].data == "", "Second result should be Loading with empty string data")
assertTrue(results[2] is Result.Error && (results[2] as Result.Error).error is Result.ErrorType.HttpError, "Third result should be Error with HttpError type")
assertEquals((results[2] as Result.Error).error?.message, errorMessage, "Error message should match expected message")

verify(apiService).sendLogout(check { it.endsWith("/api/logout") }, eq(xSession))
}

@Test
fun `sendLogout should emit Loading and Error states when network error occurs`() = runTest {
// Arrange
val serverUrl = "http://test.com"
val xSession = "testSession"
val networkErrorMessage = "Network error"
val ioException = IOException(networkErrorMessage)

`when`(apiService.sendLogout(anyString(), anyString())).thenAnswer { invocation ->
throw ioException
}

`when`(errorHandler.getError(ioException)).thenReturn(Result.ErrorType.IOError(ioException))

// Act
val results = authRepository.sendLogout(serverUrl, xSession).toList()

// Assert
assertEquals(3, results.size, "Expected 3 emitted results")
assertTrue(results[0] is Result.Loading && results[0].data == null)
assertTrue(results[1] is Result.Loading && results[1].data == "")
assertTrue(results[2] is Result.Error && (results[2] as Result.Error).error is Result.ErrorType.IOError)
assertEquals(networkErrorMessage, (results[2] as Result.Error).error?.throwable?.message)

verify(apiService).sendLogout(check { it.endsWith("/api/logout") }, eq(xSession))
}

@Test
fun `sendLoginV1 should emit Loading and Success states when API call is successful`() = runTest {
// Arrange
val username = "testUser"
val password = "testPassword"
val serverUrl = "http://test.com"
val loginResponseMessageDTO = LoginResponseMessageDTO(
expires = null,
session = null,
token = "testToken"
)
val loginResponseDTO = LoginResponseDTO(
ok = true,
message = loginResponseMessageDTO,
error = null
)
val expectedUser =
User("testToken", "testSession", Account(1, username, password, false, serverUrl, true))

`when`(apiService.sendLoginV1(anyString(), any())).thenReturn(Response.success(loginResponseDTO))
`when`(settingsPreferenceDataSource.getUser()).thenReturn(flowOf(expectedUser))

// Act
val results = authRepository.sendLoginV1(username, password, serverUrl).toList()

// Assert
assertEquals(3, results.size, "Expected 3 emitted results")
assertTrue(results[0] is Result.Loading && results[0].data == null)
assertTrue(results[1] is Result.Loading && results[1].data != null)
assertTrue(results[2] is Result.Success && results[2].data == expectedUser)

verify(settingsPreferenceDataSource).saveUser(any(), eq(serverUrl), eq(password))
verify(apiService).sendLoginV1(check { it.endsWith("/api/v1/auth/login") }, any())
}
}

Loading

0 comments on commit e3998e4

Please sign in to comment.