Test
When writing test code, it is recommended to use actual dependencies as much as possible rather than mocks. By using Koject, you can easily replace only some dependencies and test them.
Setup for Testing
To use Koject in tests, add koject-test
to the test dependencies and register koject-processor-app
to the test source set.
Multiplatform
kotlin {
/* ... */
sourceSets {
val commonMain by getting {
dependencies {
implementation("com.moriatsushi.koject:koject-core:1.3.0")
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
+ implementation("com.moriatsushi.koject:koject-test:1.3.0")
}
}
}
}
dependencies {
// Add it according to your targets.
val processor = "com.moriatsushi.koject:koject-processor-app:1.3.0"
add("kspAndroid", processor)
add("kspJvm", processor)
add("kspJs", processor)
add("kspIosX64", processor)
add("kspIosArm64", processor)
+ add("kspAndroidTest", processor)
+ add("kspJvmTest", processor)
+ add("kspJsTest", processor)
+ add("kspIosX64Test", processor)
+ add("kspIosArm64Test", processor)
}
Single platform
dependencies {
implementation("com.moriatsushi.koject:koject-core:1.3.0")
testImplementation(kotlin("test"))
+ testImplementation("com.moriatsushi.koject:koject-test:1.3.0")
+ kspTest("com.moriatsushi.koject:koject-processor-app:1.3.0")
}
Running tests
Using Koject.runTest()
, you can start the test DI container and use the provided dependencies.
@Provides
class Controller
class SampleTest() {
@Test
fun test() = Koject.runTest {
val controller = inject<Controller>() // can be injected
}
}
You can also start a test DI container by executing Koject.startTest()
in @Before
and Koject.stop()
in @After
.
class SampleTest() {
@Before
fun start() {
Koject.startTest()
}
@After
fun stop() {
Koject.stop()
}
@Test
fun test() {
val controller = inject<Controller>()
}
}
Swapping dependencies in tests
You can use @TestProvides
to replace dependencies during testing.
For example, suppose you provided and used SampleRepository as follows:
interface SampleRepository
@Provide
@Binds
class SampleRepositoryImpl: SampleRepository
fun main() {
Koject.start()
val repository = inject<SampleRepository>() // is SampleRepositoryImpl
}
During testing, you may want to use different code because you do not want to communicate with the backend server or you want to test more efficiently.
By using @TestProvides
as follows, FakeSampleRepository
is used during testing instead of SampleRepositoryImpl
.
@TestProvides
@Binds
class FakeSampleRepository: SampleRepository
class SampleTest() {
@Test
fun test() = Koject.runTest {
val repository = inject<SampleRepository>() // is FakeSampleRepository
}
}
Note that FakeSampleRepository
is not provided.
You can provide both FakeSampleRepository
and SampleRepository
by using @TestProvides
as follows.
@TestProvides
class FakeSampleRepository: SampleRepository {
companion object {
@TestProvides
fun bindAsSampleRepository(
fake: FakeSampleRepository
): SampleRepository {
return fake
}
}
}
class SampleTest() {
@Test
fun test() = Koject.runTest {
val fakeRepository = inject<FakeSampleRepository>() // is FakeSampleRepository
val repository = inject<SampleRepository>() // is FakeSampleRepository
}
}