Skip to content

Commit b16160b

Browse files
committed
ref: migrate unit tests to junit 5
1 parent 8748797 commit b16160b

File tree

18 files changed

+192
-204
lines changed

18 files changed

+192
-204
lines changed

app/build.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,11 @@ dependencies {
9494
implementation(libs.converter.gson)
9595

9696
// Unit/Integration tests dependencies
97+
testImplementation(libs.kotest.runner.junit5)
98+
testImplementation(libs.kotest.assertions.core)
99+
testImplementation(libs.kotest.property)
97100
testImplementation(libs.junit)
98101
testImplementation(libs.mockk)
99-
testImplementation(libs.kluent.android)
100102
testImplementation(libs.robolectric)
101103

102104
// UI tests dependencies

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<manifest package="com.fernandocejas.sample"
3-
xmlns:android="http://schemas.android.com/apk/res/android">
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
43

54
<!--Permissions-->
65
<uses-permission android:name="android.permission.INTERNET" />

app/src/test/kotlin/com/fernandocejas/sample/AndroidAssertions.kt

Lines changed: 0 additions & 33 deletions
This file was deleted.

app/src/test/kotlin/com/fernandocejas/sample/AndroidTest.kt

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,23 @@ package com.fernandocejas.sample
1818
import android.app.Application
1919
import android.content.Context
2020
import android.os.Build
21+
import androidx.appcompat.app.AppCompatActivity
22+
import io.kotest.matchers.string.shouldBeEqualIgnoringCase
23+
import io.mockk.MockKAnnotations
2124
import org.junit.Rule
25+
import org.junit.rules.TestRule
2226
import org.junit.runner.RunWith
27+
import org.robolectric.Robolectric
2328
import org.robolectric.RobolectricTestRunner
2429
import org.robolectric.RuntimeEnvironment
30+
import org.robolectric.Shadows
2531
import org.robolectric.annotation.Config
32+
import kotlin.reflect.KClass
2633

2734
/**
28-
* Base class for Android tests. Inherit from it to create test cases which contain android
29-
* framework dependencies or components.
35+
* Base class for Android tests. Inherit from it to
36+
* create test cases which contain android framework
37+
* dependencies or components.
3038
*
3139
* @see UnitTest
3240
*/
@@ -36,10 +44,36 @@ import org.robolectric.annotation.Config
3644
sdk = [Build.VERSION_CODES.O_MR1])
3745
abstract class AndroidTest {
3846

47+
@Rule
48+
@JvmField
3949
@Suppress("LeakingThis")
40-
@Rule @JvmField val injectMocks = InjectMocksRule.create(this@AndroidTest)
50+
val injectMocks = InjectMocksRule.create(this@AndroidTest)
4151

42-
fun context(): Context = RuntimeEnvironment.getApplication().applicationContext
52+
fun context(): Context = RuntimeEnvironment.systemContext
4353

4454
internal class ApplicationStub : Application()
55+
56+
object InjectMocksRule {
57+
fun create(testClass: Any) = TestRule { statement, _ ->
58+
MockKAnnotations.init(testClass, relaxUnitFun = true)
59+
statement
60+
}
61+
}
62+
63+
/**
64+
* Container for customized Android
65+
* specific Test Assertions.
66+
*/
67+
object AndroidAssertions {
68+
infix fun KClass<out AppCompatActivity>.shouldNavigateTo(
69+
nextActivity: KClass<out AppCompatActivity>
70+
): () -> Unit = {
71+
72+
val originActivity = Robolectric.buildActivity(this.java).get()
73+
val shadowActivity = Shadows.shadowOf(originActivity)
74+
val nextIntent = shadowActivity.peekNextStartedActivity()
75+
76+
nextIntent.component?.className shouldBeEqualIgnoringCase nextActivity.java.canonicalName!!
77+
}
78+
}
4579
}

app/src/test/kotlin/com/fernandocejas/sample/InjectMocksRule.kt

Lines changed: 0 additions & 26 deletions
This file was deleted.

app/src/test/kotlin/com/fernandocejas/sample/UnitTest.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,5 @@ import org.junit.Rule
2525
*/
2626
abstract class UnitTest {
2727

28-
@Suppress("LeakingThis")
29-
@Rule @JvmField val injectMocks = InjectMocksRule.create(this@UnitTest)
30-
3128
fun fail(message: String): Nothing = throw AssertionError(message)
3229
}

app/src/test/kotlin/com/fernandocejas/sample/core/functional/EitherTest.kt

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,52 +19,47 @@ import com.fernandocejas.sample.UnitTest
1919
import com.fernandocejas.sample.core.failure.Failure.ServerError
2020
import com.fernandocejas.sample.core.functional.Either.Left
2121
import com.fernandocejas.sample.core.functional.Either.Right
22-
import org.amshove.kluent.shouldBe
23-
import org.amshove.kluent.shouldBeInstanceOf
24-
import org.amshove.kluent.shouldEqual
25-
import org.amshove.kluent.shouldEqualTo
26-
import org.junit.Test
22+
import io.kotest.matchers.equals.shouldBeEqual
23+
import io.kotest.matchers.shouldBe
24+
import org.junit.jupiter.api.Test
2725

2826
class EitherTest : UnitTest() {
2927

30-
@Test fun `Either Right should return correct type`() {
28+
@Test
29+
fun `Either Right should return correct type`() {
3130
val result = Right("ironman")
3231

33-
result shouldBeInstanceOf Either::class.java
3432
result.isRight shouldBe true
3533
result.isLeft shouldBe false
3634
result.fold({},
3735
{ right ->
38-
right shouldBeInstanceOf String::class.java
39-
right shouldEqualTo "ironman"
36+
right shouldBeEqual "ironman"
4037
})
4138
}
4239

4340
@Test fun `Either Left should return correct type`() {
4441
val result = Left("ironman")
4542

46-
result shouldBeInstanceOf Either::class.java
4743
result.isLeft shouldBe true
4844
result.isRight shouldBe false
4945
result.fold(
5046
{ left ->
51-
left shouldBeInstanceOf String::class.java
52-
left shouldEqualTo "ironman"
47+
left shouldBeEqual "ironman"
5348
}, {})
5449
}
5550

5651
@Test fun `Either fold should ignore passed argument if it is Right type`() {
5752
val success = "Success"
5853
val result = Right(success).getOrElse("Other")
5954

60-
result shouldEqualTo success
55+
result shouldBeEqual success
6156
}
6257

6358
@Test fun `Either fold should return argument if it is Left type`() {
6459
val other = "Other"
6560
val result = Left("Failure").getOrElse(other)
6661

67-
result shouldEqual other
62+
result shouldBeEqual other
6863
}
6964

7065
@Test
@@ -96,7 +91,7 @@ class EitherTest : UnitTest() {
9691
Left(ServerError)
9792
}
9893

99-
result shouldEqual Left(ServerError)
94+
result shouldBeEqual Left(ServerError)
10095
result.isLeft shouldBe true
10196
}
10297

@@ -107,7 +102,7 @@ class EitherTest : UnitTest() {
107102
val result = either.flatMap { Right(20) }
108103

109104
result.isLeft shouldBe true
110-
result shouldEqual either
105+
result shouldBeEqual either
111106
}
112107

113108
@Test
@@ -142,7 +137,7 @@ class EitherTest : UnitTest() {
142137

143138
var methodCalled = false
144139
val result = either.onSuccess {
145-
it shouldEqual success
140+
it shouldBeEqual success
146141
methodCalled = true
147142
}
148143

@@ -170,7 +165,7 @@ class EitherTest : UnitTest() {
170165
resultValue
171166
}
172167

173-
result shouldEqual Right(resultValue)
168+
result shouldBeEqual Right(resultValue)
174169
}
175170

176171
@Test
@@ -180,6 +175,6 @@ class EitherTest : UnitTest() {
180175
val result = either.map { Right(20) }
181176

182177
result.isLeft shouldBe true
183-
result shouldEqual either
178+
result shouldBeEqual either
184179
}
185180
}

app/src/test/kotlin/com/fernandocejas/sample/core/interactor/UseCaseTest.kt

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,24 @@
1515
*/
1616
package com.fernandocejas.sample.core.interactor
1717

18-
import com.fernandocejas.sample.AndroidTest
18+
import com.fernandocejas.sample.UnitTest
1919
import com.fernandocejas.sample.core.functional.Either.Right
20+
import io.kotest.matchers.equals.shouldBeEqual
2021
import kotlinx.coroutines.runBlocking
21-
import org.amshove.kluent.shouldEqual
22-
import org.junit.Test
22+
import org.junit.jupiter.api.Test
2323

24-
class UseCaseTest : AndroidTest() {
24+
class UseCaseTest : UnitTest() {
2525

2626
private val useCase = MyUseCase()
2727

28-
@Test fun `running use case should return 'Either' of use case type`() {
28+
@Test
29+
fun `running use case should return 'Either' of use case type`() {
2930
val params = MyParams(TYPE_PARAM)
3031
val result = runBlocking { useCase.run(params) }
3132

32-
result shouldEqual Right(MyType(TYPE_TEST))
33+
result shouldBeEqual Right(MyType(TYPE_TEST))
3334
}
3435

35-
// @Test fun `should return correct data when executing use case`() {
36-
// var result: Either<Failure, MyType>? = null
37-
//
38-
// val params = MyParams("TestParam")
39-
// val onResult = { myResult: Either<Failure, MyType> -> result = myResult }
40-
//
41-
// runBlocking { useCase(params, onResult) }
42-
//
43-
// result shouldEqual Right(MyType(TYPE_TEST))
44-
// }
45-
4636
data class MyType(val name: String)
4737
data class MyParams(val name: String)
4838

app/src/test/kotlin/com/fernandocejas/sample/core/navigation/NavigatorTest.kt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
package com.fernandocejas.sample.core.navigation
1717

1818
import com.fernandocejas.sample.AndroidTest
19+
import com.fernandocejas.sample.AndroidTest.AndroidAssertions.shouldNavigateTo
1920
import com.fernandocejas.sample.features.auth.credentials.Authenticator
2021
import com.fernandocejas.sample.features.login.ui.LoginActivity
2122
import com.fernandocejas.sample.features.movies.ui.MoviesActivity
22-
import com.fernandocejas.sample.shouldNavigateTo
2323
import io.mockk.every
2424
import io.mockk.impl.annotations.MockK
2525
import io.mockk.verify
@@ -30,13 +30,16 @@ class NavigatorTest : AndroidTest() {
3030

3131
private lateinit var navigator: Navigator
3232

33-
@MockK private lateinit var authenticator: Authenticator
33+
@MockK
34+
private lateinit var authenticator: Authenticator
3435

35-
@Before fun setup() {
36+
@Before
37+
fun setup() {
3638
navigator = Navigator(authenticator)
3739
}
3840

39-
@Test fun `should forward user to login screen`() {
41+
@Test
42+
fun `should forward user to login screen`() {
4043
every { authenticator.userLoggedIn() } returns false
4144

4245
navigator.showMain(context())
@@ -45,7 +48,8 @@ class NavigatorTest : AndroidTest() {
4548
RouteActivity::class shouldNavigateTo LoginActivity::class
4649
}
4750

48-
@Test fun `should forward user to movies screen`() {
51+
@Test
52+
fun `should forward user to movies screen`() {
4953
every { authenticator.userLoggedIn() } returns true
5054

5155
navigator.showMain(context())

app/src/test/kotlin/com/fernandocejas/sample/core/platform/BaseViewModelTest.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,23 @@ import androidx.lifecycle.MutableLiveData
1919
import com.fernandocejas.sample.AndroidTest
2020
import com.fernandocejas.sample.core.failure.Failure
2121
import com.fernandocejas.sample.core.failure.Failure.NetworkConnection
22-
import org.amshove.kluent.shouldBeInstanceOf
22+
import io.kotest.matchers.should
23+
import io.kotest.matchers.types.beInstanceOf
2324
import org.junit.Test
2425

2526
class BaseViewModelTest : AndroidTest() {
2627

27-
@Test fun `should handle failure by updating live data`() {
28+
@Test
29+
fun `should handle failure by updating live data`() {
2830
val viewModel = MyViewModel()
2931

3032
viewModel.handleError(NetworkConnection)
3133

3234
val failure = viewModel.failure
3335
val error = viewModel.failure.value
3436

35-
failure shouldBeInstanceOf MutableLiveData::class.java
36-
error shouldBeInstanceOf NetworkConnection::class.java
37+
failure should beInstanceOf<MutableLiveData<Failure>>()
38+
error should beInstanceOf<NetworkConnection>()
3739
}
3840

3941
private class MyViewModel : BaseViewModel() {

0 commit comments

Comments
 (0)