Repository Unit Tests #50
@ -56,6 +56,8 @@ kotlin {
|
||||
dependencies {
|
||||
implementation(kotlin("test-common"))
|
||||
implementation(kotlin("test-annotations-common"))
|
||||
implementation("io.mockk:mockk:1.12.0")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
|
||||
}
|
||||
}
|
||||
val androidMain by getting {
|
||||
|
@ -11,6 +11,7 @@ import io.github.aakira.napier.Napier
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
class Repository(private val api: SelfossApi, private val appSettingsService: AppSettingsService, connectivityStatus: ConnectivityStatus, private val db: ReaderForSelfossDB) {
|
||||
|
||||
@ -38,7 +39,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
||||
|
||||
init {
|
||||
// TODO: Dispatchers.IO not available in KMM, an alternative solution should be found
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
runBlocking {
|
||||
AmineB marked this conversation as resolved
Outdated
|
||||
updateApiVersion()
|
||||
dateUtils = DateUtils(appSettingsService)
|
||||
reloadBadges()
|
||||
|
@ -0,0 +1,68 @@
|
||||
package bou.amine.apps.readerforselfossv2.repository
|
||||
|
||||
import bou.amine.apps.readerforselfossv2.dao.ITEM
|
||||
import bou.amine.apps.readerforselfossv2.dao.ReaderForSelfossDB
|
||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
|
||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||
import com.github.ln_12.library.ConnectivityStatus
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlin.test.BeforeTest
|
||||
import kotlin.test.Test
|
||||
|
||||
class RepositoryTest() {
|
||||
private val connectivityStatus = mockk<ConnectivityStatus>()
|
||||
private val db = mockk<ReaderForSelfossDB>()
|
||||
private val appSettingsService = mockk<AppSettingsService>()
|
||||
private val api = mockk<SelfossApi>()
|
||||
|
||||
@BeforeTest
|
||||
fun setup() {
|
||||
every { appSettingsService.getApiVersion() } returns 4
|
||||
every { appSettingsService.getBaseUrl() } returns "https://test.com/selfoss/"
|
||||
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(true)
|
||||
|
||||
coEvery { api.version() } returns SelfossModel.ApiVersion("2.19-ba1e8e3", "4.0.0")
|
||||
coEvery { api.stats() } returns SelfossModel.Stats(100, 50, 20)
|
||||
|
||||
every { db.itemsQueries.items().executeAsList() } returns generateTestDBItems()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Instantiate repository`() {
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Instantiate repository without api version`() {
|
||||
every { appSettingsService.getApiVersion() } returns -1
|
||||
every { connectivityStatus.isNetworkConnected } returns MutableStateFlow(false)
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
}
|
||||
|
||||
AmineB marked this conversation as resolved
AmineB
commented
This does not seem to do anything. Is it needed ? This does not seem to do anything. Is it needed ?
davidoskky
commented
The test can fail if the repository initialization generates an error; this is just a very general case to identify if something in the repository initialization is broken. The test can fail if the repository initialization generates an error; this is just a very general case to identify if something in the repository initialization is broken.
All other tests would fail as well, but this will give you certainty that the point of failure is in the initialization.
AmineB
commented
The way I understand your comment is that sometimes, the repository can fail an throw an error. This should not be handled in a unit test, but handled in the code. The exception should be catched and handled there. You can keep your tests, but the call should return something, and the tests should actually test something. Same for the three following tests. The way I understand your comment is that sometimes, the repository can fail an throw an error.
This should not be handled in a unit test, but handled in the code.
The exception should be catched and handled there.
You can keep your tests, but the call should return something, and the tests should actually **test** something.
Same for the three following tests.
|
||||
@Test
|
||||
fun `Instantiate repository with negative stats`() {
|
||||
AmineB marked this conversation as resolved
Outdated
AmineB
commented
As mentionnend in my previous comment. The try catch must be in the code, not in the unit test.
As mentionnend in my previous comment. The try catch must be in the code, not in the unit test.
AmineB
commented
Same for all the other try catch in here. Same for all the other try catch in here.
davidoskky
commented
I'm not sure how I would implement this test otherwise, I guess the repository should raise an exception during initialization then. I'm not sure how I would implement this test otherwise, I guess the repository should raise an exception during initialization then.
AmineB
commented
Yep. That should be the case. > I guess the repository should raise an exception during initialization then.
Yep. That should be the case.
|
||||
coEvery { api.stats() } returns SelfossModel.Stats(-100, -50, -20)
|
||||
|
||||
val repository = Repository(api, appSettingsService, connectivityStatus, db)
|
||||
AmineB marked this conversation as resolved
Outdated
AmineB
commented
This does not seem to do anything. Is it needed ? This does not seem to do anything. Is it needed ?
davidoskky
commented
Same as above. Same as above.
|
||||
}
|
||||
}
|
||||
|
||||
fun generateTestDBItems() = listOf(ITEM(
|
||||
id = "20",
|
||||
datetime = "2022-09-09T03:32:01-04:00",
|
||||
title = "Etica della ricerca sotto i riflettori.",
|
||||
content = "<p><strong>Luigi Campanella, già Presidente SCI</strong></p>\n<p>L’etica della scienza è di certo ambito di cui continuiamo a scoprire nuovi aspetti e risvolti.</p>\n<p>L’ultimo è quello delle intelligenze artificiali capaci di creare opere complesse basate su immagini e parole memorizzate con il rischio di fake news e di contenuti disturbanti.</p>\n<p>Per evitare che ciò accada si sta procedendo filtrando secondo criteri di autocensura i dati da cui l’intelligenza artificiale parte.</p>\n<p>Comincia ad intravedersi un futuro prossimo di competizione fra autori umani ed artificiali nel quale sarà importante, quando i loro prodotti saranno indistinguibili, dichiararne l’origine.</p>\n<p>Come si comprende, si conferma che gli aspetti etici dell’innovazione e della ricerca si diversificato sempre di più.</p>\n<p>La biologia molecolare e la genetica già in passato hanno posto all’attenzione comune aspetti di etica della scienza che hanno indotto a nuove riflessioni circa i limiti delle ricerche.</p>\n<p>L’argomento, sempre attuale, torna sulle prime pagine a seguito della pubblicazione di una ricerca della Università di Cambridge che ha sviluppato una struttura cellulare di un topo con un cuore che batte regolarmente.</p>\n<img src=\"https://ilblogdellasci.files.wordpress.com/2022/09/image002-1.png?w=481\" alt=\"\" width=\"697\" height=\"430\" /><img src=\"https://ilblogdellasci.files.wordpress.com/2022/09/image003-1.png?w=906\" alt=\"\" /><p>Magdalena Zernicka-Goetz</p>\n<img src=\"https://ilblogdellasci.files.wordpress.com/2022/09/image004.jpg?w=474\" alt=\"\" width=\"622\" height=\"465\" /><p>Gianluca Amadei</p>\n<p>Del gruppo fa parte anche uno scienziato italiano Gianluca Amadei,che dinnanzi alle obiezioni di natura etica sulla realizzazione della vita artificiale si è affrettato a sostenere che non è creare nuove vite il fine primario della ricerca, ma quello di salvare quelle esistenti, di dare contributi essenziali alla medicina citando il caso del fallimento tuttora non interpretato di alcune gravidanze e di superare la sperimentazione animale, così contribuendo positivamente alla soluzione di un altro dilemma etico.</p>\n<p>L’embrione sintetico ha ovviamente come primo traguardo il contributo ai trapianti oggi drammaticamente carenti nell’offerta rispetto alla domanda, con attese fino a 4 anni per i trapianti di cuore ed a 2 anni per quelli di fegato. Il lavoro dovrebbe adesso continuare presso l’Ateneo di Padova per creare nuovi organi e nuovi farmaci.</p>",
|
||||
AmineB marked this conversation as resolved
Outdated
AmineB
commented
This does not seem to do anything. Is it needed ? This does not seem to do anything. Is it needed ?
davidoskky
commented
Same as above. Same as above.
|
||||
unread = true,
|
||||
starred = true,
|
||||
thumbnail = null,
|
||||
icon = "ba79e238383ce83c23a169929c8906ef.png",
|
||||
link = "https://ilblogdellasci.wordpress.com/2022/09/09/etica-della-ricerca-sotto-i-riflettori/",
|
||||
sourcetitle = "La Chimica e la Società",
|
||||
tags = "Chimica, Testing"
|
||||
))
|
What does this change do ?
This does not change the behavior of the function at all.
runBlocking and Dispatchers.Main are basically the same thing.
However, the testing framework for the common code does not support Dispatchers.
This edit serves pretty much just to make the tests work properly.
I'm certain there is some way to make it work keeping the Dispatchers in there, but since these are equivalent I preferred saving some time and just slightly change the function.