Skip to content
Snippets Groups Projects
Unverified Commit 3b02e2c4 authored by Chilja Gossow's avatar Chilja Gossow Committed by GitHub
Browse files

Add unit tests (EXPOSUREAPP-4821) #2498


* data storage and collection

* collect data

* storage

* repository

* collect data

* collect data

* revert unrelated changes

* revert unrelated changes

* fix tests

* fix tests

* fix instrumentation tests

* review comments

* submitted at

* submitted at

* fix test

* fix test

* add unit tests

* add unit tests

* fix test

* comments
fix test result donor calculation

Co-authored-by: default avatarRalf Gehrer <ralfgehrer@users.noreply.github.com>
parent e60e21c5
No related branches found
No related tags found
No related merge requests found
Showing
with 453 additions and 10 deletions
package de.rki.coronawarnapp.datadonation.analytics.common
import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDate
import org.joda.time.Days
import org.joda.time.Instant
fun calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration(
lastChangeCheckedRiskLevelTimestamp: Instant?,
testRegisteredAt: Instant?
): Int {
val lastChangeCheckedRiskLevelDate = lastChangeCheckedRiskLevelTimestamp?.toLocalDate() ?: return 0
val testRegisteredAtDate = testRegisteredAt?.toLocalDate() ?: return 0
return Days.daysBetween(
lastChangeCheckedRiskLevelDate,
testRegisteredAtDate
).days
}
...@@ -11,7 +11,7 @@ import javax.inject.Singleton ...@@ -11,7 +11,7 @@ import javax.inject.Singleton
@Singleton @Singleton
class AnalyticsKeySubmissionDonor @Inject constructor( class AnalyticsKeySubmissionDonor @Inject constructor(
val repository: AnalyticsKeySubmissionRepository, private val repository: AnalyticsKeySubmissionRepository,
private val timeStamper: TimeStamper private val timeStamper: TimeStamper
) : DonorModule { ) : DonorModule {
...@@ -54,7 +54,8 @@ class AnalyticsKeySubmissionDonor @Inject constructor( ...@@ -54,7 +54,8 @@ class AnalyticsKeySubmissionDonor @Inject constructor(
.setSubmittedInBackground(repository.submittedInBackground) .setSubmittedInBackground(repository.submittedInBackground)
.setSubmittedWithTeleTAN(repository.submittedWithTeleTAN) .setSubmittedWithTeleTAN(repository.submittedWithTeleTAN)
private fun shouldSubmitData(timeSinceTestResultToSubmit: Duration): Boolean { @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
internal fun shouldSubmitData(timeSinceTestResultToSubmit: Duration): Boolean {
return positiveTestResultReceived && ( return positiveTestResultReceived && (
keysSubmitted || enoughTimeHasPassedSinceResult(timeSinceTestResultToSubmit) keysSubmitted || enoughTimeHasPassedSinceResult(timeSinceTestResultToSubmit)
) )
...@@ -66,7 +67,8 @@ class AnalyticsKeySubmissionDonor @Inject constructor( ...@@ -66,7 +67,8 @@ class AnalyticsKeySubmissionDonor @Inject constructor(
private val keysSubmitted: Boolean private val keysSubmitted: Boolean
get() = repository.submitted get() = repository.submitted
private fun enoughTimeHasPassedSinceResult(timeSinceTestResultToSubmit: Duration): Boolean = @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
internal fun enoughTimeHasPassedSinceResult(timeSinceTestResultToSubmit: Duration): Boolean =
timeStamper.nowUTC.minus(timeSinceTestResultToSubmit) > Instant.ofEpochMilli(repository.testResultReceivedAt) timeStamper.nowUTC.minus(timeSinceTestResultToSubmit) > Instant.ofEpochMilli(repository.testResultReceivedAt)
override suspend fun deleteData() { override suspend fun deleteData() {
...@@ -74,7 +76,7 @@ class AnalyticsKeySubmissionDonor @Inject constructor( ...@@ -74,7 +76,7 @@ class AnalyticsKeySubmissionDonor @Inject constructor(
} }
} }
@VisibleForTesting @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
object AnalyticsKeySubmissionNoContribution : DonorModule.Contribution { object AnalyticsKeySubmissionNoContribution : DonorModule.Contribution {
override suspend fun injectData(protobufContainer: PpaData.PPADataAndroid.Builder) = Unit override suspend fun injectData(protobufContainer: PpaData.PPADataAndroid.Builder) = Unit
override suspend fun finishDonation(successful: Boolean) = Unit override suspend fun finishDonation(successful: Boolean) = Unit
......
package de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission package de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission
import de.rki.coronawarnapp.datadonation.analytics.common.calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration
import de.rki.coronawarnapp.risk.RiskLevelSettings import de.rki.coronawarnapp.risk.RiskLevelSettings
import org.joda.time.Duration import org.joda.time.Duration
import org.joda.time.Instant import org.joda.time.Instant
...@@ -47,10 +48,10 @@ class AnalyticsKeySubmissionRepository @Inject constructor( ...@@ -47,10 +48,10 @@ class AnalyticsKeySubmissionRepository @Inject constructor(
get() = Duration.millis(max(submittedAt - testRegisteredAt, 0L)).toStandardHours().hours get() = Duration.millis(max(submittedAt - testRegisteredAt, 0L)).toStandardHours().hours
val daysSinceMostRecentDateAtRiskLevelAtTestRegistration: Int val daysSinceMostRecentDateAtRiskLevelAtTestRegistration: Int
get() = Duration( get() = calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration(
riskLevelSettings.lastChangeCheckedRiskLevelTimestamp, riskLevelSettings.lastChangeCheckedRiskLevelTimestamp,
Instant.ofEpochMilli(testRegisteredAt) Instant.ofEpochMilli(testRegisteredAt)
).standardDays.toInt() )
val hoursSinceHighRiskWarningAtTestRegistration: Int val hoursSinceHighRiskWarningAtTestRegistration: Int
get() = storage.hoursSinceHighRiskWarningAtTestRegistration.value get() = storage.hoursSinceHighRiskWarningAtTestRegistration.value
......
package de.rki.coronawarnapp.datadonation.analytics.modules.registeredtest package de.rki.coronawarnapp.datadonation.analytics.modules.registeredtest
import de.rki.coronawarnapp.datadonation.analytics.common.calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration
import de.rki.coronawarnapp.datadonation.analytics.modules.DonorModule import de.rki.coronawarnapp.datadonation.analytics.modules.DonorModule
import de.rki.coronawarnapp.datadonation.analytics.storage.TestResultDonorSettings import de.rki.coronawarnapp.datadonation.analytics.storage.TestResultDonorSettings
import de.rki.coronawarnapp.risk.RiskLevelSettings import de.rki.coronawarnapp.risk.RiskLevelSettings
...@@ -50,10 +51,10 @@ class TestResultDonor @Inject constructor( ...@@ -50,10 +51,10 @@ class TestResultDonor @Inject constructor(
testResultDonorSettings.testResultAtRegistration.value ?: return TestResultMetadataNoContribution testResultDonorSettings.testResultAtRegistration.value ?: return TestResultMetadataNoContribution
val daysSinceMostRecentDateAtRiskLevelAtTestRegistration = val daysSinceMostRecentDateAtRiskLevelAtTestRegistration =
Duration( calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration(
riskLevelSettings.lastChangeCheckedRiskLevelTimestamp, riskLevelSettings.lastChangeCheckedRiskLevelTimestamp,
registrationTime registrationTime
).standardDays.toInt() )
val riskLevelAtRegistration = testResultDonorSettings.riskLevelAtTestRegistration.value val riskLevelAtRegistration = testResultDonorSettings.riskLevelAtTestRegistration.value
......
package de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission package de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission
class AnalyticsKeySubmissionCollectorTest import de.rki.coronawarnapp.datadonation.analytics.storage.AnalyticsSettings
import de.rki.coronawarnapp.risk.RiskLevelResult
import de.rki.coronawarnapp.risk.RiskLevelSettings
import de.rki.coronawarnapp.risk.RiskState
import de.rki.coronawarnapp.risk.storage.RiskLevelStorage
import de.rki.coronawarnapp.util.TimeStamper
import io.mockk.MockKAnnotations
import io.mockk.coEvery
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.verify
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runBlockingTest
import org.joda.time.Hours
import org.joda.time.Instant
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import testhelpers.BaseTest
import testhelpers.preferences.mockFlowPreference
class AnalyticsKeySubmissionCollectorTest : BaseTest() {
@MockK lateinit var timeStamper: TimeStamper
@MockK lateinit var analyticsSettings: AnalyticsSettings
@MockK lateinit var analyticsKeySubmissionStorage: AnalyticsKeySubmissionStorage
@MockK lateinit var riskLevelStorage: RiskLevelStorage
@MockK lateinit var riskLevelSettings: RiskLevelSettings
@MockK lateinit var riskLevelResult: RiskLevelResult
private val now = Instant.now()
@BeforeEach
fun setup() {
MockKAnnotations.init(this)
every { timeStamper.nowUTC } returns now
}
@Test
fun `save test registered`() {
coEvery { analyticsSettings.analyticsEnabled.value } returns true
every { riskLevelResult.riskState } returns RiskState.INCREASED_RISK
coEvery {
riskLevelStorage.latestAndLastSuccessful
} returns flowOf(listOf(riskLevelResult))
every { riskLevelSettings.lastChangeToHighRiskLevelTimestamp } returns now.minus(
Hours.hours(2).toStandardDuration()
)
val testRegisteredAt = mockFlowPreference(now.millis)
coEvery { analyticsKeySubmissionStorage.testRegisteredAt } returns testRegisteredAt
every { riskLevelResult.wasSuccessfullyCalculated } returns true
val riskLevelAtTestRegistration = mockFlowPreference(-1)
every { analyticsKeySubmissionStorage.riskLevelAtTestRegistration } returns riskLevelAtTestRegistration
val hoursSinceHighRiskWarningAtTestRegistration = mockFlowPreference(-1)
every { analyticsKeySubmissionStorage.hoursSinceHighRiskWarningAtTestRegistration } returns hoursSinceHighRiskWarningAtTestRegistration
runBlockingTest {
val collector = createInstance()
collector.reportTestRegistered()
verify { testRegisteredAt.update(any()) }
verify { riskLevelAtTestRegistration.update(any()) }
verify { hoursSinceHighRiskWarningAtTestRegistration.update(any()) }
}
}
@Test
fun `save keys submitted`() {
coEvery { analyticsSettings.analyticsEnabled.value } returns true
val submittedFlow = mockFlowPreference(false)
every { analyticsKeySubmissionStorage.submitted } returns submittedFlow
val submittedAtFlow = mockFlowPreference(now.millis)
every { analyticsKeySubmissionStorage.submittedAt } returns submittedAtFlow
runBlockingTest {
val collector = createInstance()
collector.reportSubmitted()
verify { submittedFlow.update(any()) }
verify { submittedAtFlow.update(any()) }
}
}
@Test
fun `save keys submitted after cancel`() {
coEvery { analyticsSettings.analyticsEnabled.value } returns true
val flow = mockFlowPreference(false)
every { analyticsKeySubmissionStorage.submittedAfterCancel } returns flow
runBlockingTest {
val collector = createInstance()
collector.reportSubmittedAfterCancel()
verify { flow.update(any()) }
}
}
@Test
fun `save keys submitted in background`() {
coEvery { analyticsSettings.analyticsEnabled.value } returns true
val flow = mockFlowPreference(false)
every { analyticsKeySubmissionStorage.submittedInBackground } returns flow
runBlockingTest {
val collector = createInstance()
collector.reportSubmittedInBackground()
verify { flow.update(any()) }
}
}
@Test
fun `save keys submitted after symptom flow`() {
coEvery { analyticsSettings.analyticsEnabled.value } returns true
val flow = mockFlowPreference(false)
every { analyticsKeySubmissionStorage.submittedAfterSymptomFlow } returns flow
runBlockingTest {
val collector = createInstance()
collector.reportSubmittedAfterSymptomFlow()
verify { flow.update(any()) }
}
}
@Test
fun `save positive test result received`() {
coEvery { analyticsSettings.analyticsEnabled.value } returns true
val flow = mockFlowPreference(now.millis)
every { analyticsKeySubmissionStorage.testResultReceivedAt } returns flow
runBlockingTest {
val collector = createInstance()
collector.reportPositiveTestResultReceived()
verify { flow.update(any()) }
}
}
@Test
fun `save advanced consent given`() {
coEvery { analyticsSettings.analyticsEnabled.value } returns true
val flow = mockFlowPreference(false)
every { analyticsKeySubmissionStorage.advancedConsentGiven } returns flow
runBlockingTest {
val collector = createInstance()
collector.reportAdvancedConsentGiven()
verify { flow.update(any()) }
}
}
@Test
fun `save consent withdrawn`() {
coEvery { analyticsSettings.analyticsEnabled.value } returns true
val flow = mockFlowPreference(false)
every { analyticsKeySubmissionStorage.advancedConsentGiven } returns flow
runBlockingTest {
val collector = createInstance()
collector.reportConsentWithdrawn()
verify { flow.update(any()) }
}
}
@Test
fun `save registered with tele tan`() {
coEvery { analyticsSettings.analyticsEnabled.value } returns true
val flow = mockFlowPreference(false)
every { analyticsKeySubmissionStorage.registeredWithTeleTAN } returns flow
runBlockingTest {
val collector = createInstance()
collector.reportRegisteredWithTeleTAN()
verify { flow.update(any()) }
}
}
@Test
fun `save last submission flow screen`() {
coEvery { analyticsSettings.analyticsEnabled.value } returns true
val flow = mockFlowPreference(0)
every { analyticsKeySubmissionStorage.lastSubmissionFlowScreen } returns flow
runBlockingTest {
val collector = createInstance()
collector.reportLastSubmissionFlowScreen(Screen.WARN_OTHERS)
verify { flow.update(any()) }
}
}
@Test
fun `no data collection if disabled`() {
coEvery { analyticsSettings.analyticsEnabled.value } returns false
runBlockingTest {
val collector = createInstance()
collector.reportTestRegistered()
verify(exactly = 0) { analyticsKeySubmissionStorage.testRegisteredAt }
verify(exactly = 0) { analyticsKeySubmissionStorage.riskLevelAtTestRegistration }
verify(exactly = 0) { analyticsKeySubmissionStorage.hoursSinceHighRiskWarningAtTestRegistration }
collector.reportSubmitted()
verify(exactly = 0) { analyticsKeySubmissionStorage.submitted }
collector.reportSubmittedInBackground()
verify(exactly = 0) { analyticsKeySubmissionStorage.submittedInBackground }
collector.reportAdvancedConsentGiven()
verify(exactly = 0) { analyticsKeySubmissionStorage.advancedConsentGiven }
collector.reportConsentWithdrawn()
verify(exactly = 0) { analyticsKeySubmissionStorage.advancedConsentGiven }
collector.reportLastSubmissionFlowScreen(Screen.UNKNOWN)
verify(exactly = 0) { analyticsKeySubmissionStorage.lastSubmissionFlowScreen }
collector.reportPositiveTestResultReceived()
verify(exactly = 0) { analyticsKeySubmissionStorage.testResultReceivedAt }
collector.reportSubmittedAfterCancel()
verify(exactly = 0) { analyticsKeySubmissionStorage.submittedAfterCancel }
}
}
fun createInstance() = AnalyticsKeySubmissionCollector(
timeStamper,
analyticsSettings,
analyticsKeySubmissionStorage,
riskLevelStorage,
riskLevelSettings
)
}
package de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission package de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission
class AnalyticsKeySubmissionDonorTest import de.rki.coronawarnapp.appconfig.ConfigData
import de.rki.coronawarnapp.datadonation.analytics.modules.DonorModule
import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpaData
import de.rki.coronawarnapp.util.TimeStamper
import io.kotest.matchers.shouldBe
import io.mockk.MockKAnnotations
import io.mockk.Runs
import io.mockk.coVerify
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.just
import io.mockk.verify
import kotlinx.coroutines.test.runBlockingTest
import org.joda.time.Duration
import org.joda.time.Instant
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import testhelpers.BaseTest
class AnalyticsKeySubmissionDonorTest : BaseTest() {
@MockK lateinit var repository: AnalyticsKeySubmissionRepository
@MockK lateinit var timeStamper: TimeStamper
@MockK lateinit var configData: ConfigData
private val request = object : DonorModule.Request {
override val currentConfig: ConfigData
get() = configData
}
private val now = Instant.now()
@MockK lateinit var ppaData: PpaData.PPADataAndroid.Builder
@BeforeEach
fun setup() {
MockKAnnotations.init(this)
every { timeStamper.nowUTC } returns now
every { configData.analytics.hoursSinceTestResultToSubmitKeySubmissionMetadata } returns 6
}
@Test
fun `no contribution without test result`() {
every { repository.testResultReceivedAt } returns -1
every { repository.submitted } returns false
runBlockingTest {
val donor = createInstance()
donor.beginDonation(request) shouldBe AnalyticsKeySubmissionNoContribution
}
}
@Test
fun `no contribution when neither submitted nor enough time passed`() {
every { repository.testResultReceivedAt } returns now.minus(Duration.standardHours(4)).millis
every { repository.submitted } returns false
runBlockingTest {
val donor = createInstance()
donor.beginDonation(request) shouldBe AnalyticsKeySubmissionNoContribution
}
}
@Test
fun `regular contribution when keys submitted`() {
every { repository.testResultReceivedAt } returns now.minus(Duration.standardHours(4)).millis
every { repository.advancedConsentGiven } returns true
every { repository.daysSinceMostRecentDateAtRiskLevelAtTestRegistration } returns 1
every { repository.hoursSinceHighRiskWarningAtTestRegistration } returns 1
every { repository.hoursSinceTestResult } returns 1
every { repository.hoursSinceTestRegistration } returns 1
every { repository.lastSubmissionFlowScreen } returns 1
every { repository.submittedAfterCancel } returns true
every { repository.submittedAfterSymptomFlow } returns true
every { repository.submittedInBackground } returns true
every { repository.submittedWithTeleTAN } returns false
every { repository.submitted } returns true
every { ppaData.addKeySubmissionMetadataSet(any<PpaData.PPAKeySubmissionMetadata.Builder>()) } returns ppaData
every { repository.reset() } just Runs
runBlockingTest {
val donor = createInstance()
val contribution = donor.beginDonation(request)
contribution.injectData(ppaData)
coVerify { ppaData.addKeySubmissionMetadataSet(any<PpaData.PPAKeySubmissionMetadata.Builder>()) }
contribution.finishDonation(false)
verify(exactly = 0) { repository.reset() }
contribution.finishDonation(true)
verify(exactly = 1) { repository.reset() }
}
}
@Test
fun `submit contribution after enough time has passed`() {
every { repository.testResultReceivedAt } returns now.minus(Duration.standardHours(4)).millis
every { repository.submitted } returns true
val minTimePassedToSubmit = Duration.standardHours(3)
runBlockingTest {
val donor = createInstance()
donor.enoughTimeHasPassedSinceResult(Duration.standardHours(3)) shouldBe true
donor.shouldSubmitData(minTimePassedToSubmit) shouldBe true
}
}
fun createInstance() = AnalyticsKeySubmissionDonor(repository, timeStamper)
}
package de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission
import de.rki.coronawarnapp.risk.RiskLevelSettings
import io.kotest.matchers.shouldBe
import io.mockk.MockKAnnotations
import io.mockk.coEvery
import io.mockk.impl.annotations.MockK
import org.joda.time.Days
import org.joda.time.Hours
import org.joda.time.Instant
import org.joda.time.LocalTime
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import testhelpers.BaseTest
class AnalyticsKeySubmissionRepositoryTest : BaseTest() {
@MockK lateinit var storage: AnalyticsKeySubmissionStorage
@MockK lateinit var riskLevelSettings: RiskLevelSettings
private val now = Instant.now()
@BeforeEach
fun setup() {
MockKAnnotations.init(this)
}
private fun createInstance() = AnalyticsKeySubmissionRepository(
storage, riskLevelSettings
)
@Test
fun `hours since test result are calculated correctly`() {
coEvery { storage.submittedAt.value } returns now.millis
coEvery { storage.testResultReceivedAt.value } returns now.minus(Hours.hours(5).toStandardDuration()).millis
val repository = createInstance()
repository.hoursSinceTestResult shouldBe 5
}
@Test
fun `hours since test result when not submitted should be 0`() {
coEvery { storage.submittedAt.value } returns -1
coEvery { storage.testResultReceivedAt.value } returns now.minus(Hours.hours(5).toStandardDuration()).millis
val repository = createInstance()
repository.hoursSinceTestResult shouldBe 0
}
@Test
fun `hours since test result when not received or submitted should be 0`() {
coEvery { storage.submittedAt.value } returns -1
coEvery { storage.testResultReceivedAt.value } returns -1
val repository = createInstance()
repository.hoursSinceTestResult shouldBe 0
}
@Test
fun `hours since test result should be 0 when dates have been manipulated`() {
coEvery { storage.submittedAt.value } returns now.minus(Hours.hours(5).toStandardDuration()).millis
coEvery { storage.testResultReceivedAt.value } returns now.millis
val repository = createInstance()
repository.hoursSinceTestResult shouldBe 0
}
@Test
fun `hours since test registration are calculated correctly`() {
coEvery { storage.submittedAt.value } returns now.millis
coEvery { storage.testRegisteredAt.value } returns now.minus(Hours.hours(5).toStandardDuration()).millis
val repository = createInstance()
repository.hoursSinceTestRegistration shouldBe 5
}
@Test
fun `hours since test registration should be 0 if not submitted`() {
coEvery { storage.submittedAt.value } returns -1
coEvery { storage.testRegisteredAt.value } returns now.minus(Hours.hours(5).toStandardDuration()).millis
val repository = createInstance()
repository.hoursSinceTestRegistration shouldBe 0
}
@Test
fun `days since most recent date at risk level at test registration are calculated correctly`() {
coEvery {
riskLevelSettings.lastChangeCheckedRiskLevelTimestamp
} returns now
.minus(Days.days(2).toStandardDuration()).toDateTime().toLocalDate()
.toDateTime(LocalTime(22, 0)).toInstant()
coEvery { storage.testRegisteredAt.value } returns
now.toDateTime().toLocalDate().toDateTime(LocalTime(5, 0)).millis
val repository = createInstance()
repository.daysSinceMostRecentDateAtRiskLevelAtTestRegistration shouldBe 2
}
@Test
fun `days between most recent risk level change and test registration should be 0 if on same day`() {
coEvery {
riskLevelSettings.lastChangeCheckedRiskLevelTimestamp
} returns now
.toDateTime().toLocalDate()
.toDateTime(LocalTime(13, 0)).toInstant()
coEvery { storage.testRegisteredAt.value } returns
now.toDateTime().toLocalDate().toDateTime(LocalTime(14, 0)).millis
val repository = createInstance()
repository.daysSinceMostRecentDateAtRiskLevelAtTestRegistration shouldBe 0
}
@Test
fun `days should be 0 if lastChangeCheckedRiskLevelTimestamp is null`() {
coEvery {
riskLevelSettings.lastChangeCheckedRiskLevelTimestamp
} returns null
coEvery { storage.testRegisteredAt.value } returns
now.toDateTime().toLocalDate().toDateTime(LocalTime(14, 0)).millis
val repository = createInstance()
repository.daysSinceMostRecentDateAtRiskLevelAtTestRegistration shouldBe 0
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment