sam
11/02/2021, 3:24 PMdave08
11/03/2021, 1:09 PMsam
11/03/2021, 1:10 PMdave08
11/03/2021, 1:11 PMclass KtorExtension(val module: Application.() -> Unit) : TestListener {
lateinit var appEngine: TestApplicationEngine
lateinit var clientEngine: HttpClientEngine
override suspend fun beforeTest(testCase: TestCase) {
appEngine = TestApplicationEngine(createTestEnvironment())
.also { it.application.module() }
clientEngine = TestHttpClientEngine.create { app = appEngine }
appEngine.start()
}
override suspend fun afterTest(testCase: TestCase, result: TestResult) {
appEngine.stop(0L, 0L)
}
}
is this the right way to do it?sam
11/03/2021, 1:11 PMclass KtorExtension(val module: Application.() -> Unit) : BeforeTestListener, AfterTestListener {
lateinit var appEngine: TestApplicationEngine
lateinit var clientEngine: HttpClientEngine
override suspend fun beforeTest(testCase: TestCase) {
appEngine = TestApplicationEngine(createTestEnvironment())
.also { it.application.module() }
clientEngine = TestHttpClientEngine.create { app = appEngine }
appEngine.start()
}
override suspend fun afterTest(testCase: TestCase, result: TestResult) {
appEngine.stop(0L, 0L)
}
}
dave08
11/03/2021, 1:12 PMsam
11/03/2021, 1:12 PMdave08
11/03/2021, 1:13 PMsam
11/03/2021, 1:13 PMextension
is anything you write that plugs into the kotest lifecycle - so before/after test/spec/project / etc.
A listener
is an older term we had that basically means "an extension that is read only". So notice in your example that you are notified of before/after test but you can't "change the engine". So that's a listener.
An extension is just more powerful can do things like override test results, or skip tests entirely, etc.dave08
11/03/2021, 1:14 PMsam
11/03/2021, 1:14 PMTestListener
won't be renamed as it's used by everyone, but what does this do:
interface Listener: Extension
interface Extension
dave08
11/03/2021, 1:18 PMsam
11/03/2021, 1:19 PMclass MyTest : FunSpec() {
override fun extensions() = listOf(foo)
override fun listeners() = listOf(bar)
}
class MyTest : FunSpec() {
override fun extensions() = listOf(foo, bar)
}
dave08
11/03/2021, 1:21 PMBeforeTestListener
is an extension when the concept of Extension
is something a bit more flexible. I guess the docs could be a big help do disambiguate things though...sam
11/03/2021, 1:23 PMdave08
11/03/2021, 1:24 PMval dep1 get() = component.dep1()
would be nice...sam
11/03/2021, 1:27 PMdave08
11/03/2021, 1:31 PMclass SomeSpec @Inject constructor(val dep1: Dep1) { ... }
// component interface
interface TestComponent {
val someSpec: SomeSpec
}
// Will generate DaggerTestComponent, and then to build the graph:
val component = DaggerTestComponent.builder().build()
// And to retreive the injected spec:
component.someSpec
sam
11/03/2021, 1:32 PMsomeSpec
get inside the component ?dave08
11/03/2021, 1:33 PMDaggerTestComponent
that derives from TestComponent
with all the object initialization codesam
11/03/2021, 1:33 PMdave08
11/03/2021, 1:34 PMsam
11/03/2021, 1:34 PMclass DaggerExtension : PostInstantiationExtension {
override suspend fun instantiated(spec: Spec): Spec {
// get component somehow ? by casting ?
return component.someSpec
}
}
ConstructorExtension
dave08
11/03/2021, 1:36 PMsam
11/03/2021, 1:40 PMdave08
11/03/2021, 2:08 PMinterface TestComponent {
fun inject(spec: SomeSpec)
}
val component = DaggerTestComponent.builder().build()
class SomeSpec : DescribeSpec() {
@Inject val dep1 : Dep1
}
I have to get the PostInstantiationExtension
to run component.inject(this@SomeSpec)
somehow... so that dep1 gets injected...class DaggerExtension<C : Any, S : KotestDbSpec>(val component: C, val injector: (S) -> Unit) : PostInstantiationExtension {
override fun process(spec: Spec): Spec = spec.also { component/*...?*/ }
}
sam
11/03/2021, 2:09 PMdave08
11/03/2021, 2:11 PMclass DaggerExtension<C : Any, S : KotestDbSpec>(val component: C, val injector: C.(S) -> Unit) : PostInstantiationExtension {
override fun process(spec: Spec): Spec = spec.also { component.injector(spec as S) }
}
?sam
11/03/2021, 2:12 PMdave08
11/03/2021, 2:13 PM@Override
public void inject(GetCustomerSpec getCustomerSpec) {
injectGetCustomerSpec(getCustomerSpec);
}
private GetCustomerSpec injectGetCustomerSpec(GetCustomerSpec instance) {
GetCustomerSpec_MembersInjector.injectCustomerRepo(instance, customerTestRepoProvider.get());
return instance;
}
sam
11/03/2021, 2:14 PMDaggerTestComponent
and is there one per spec ?dave08
11/03/2021, 2:15 PMsam
11/03/2021, 2:16 PMClass.forName(Dagger + kclass.name)
to get the class referencedave08
11/03/2021, 2:18 PMfun inject(spec: SomeSpec)
, I don't need to create the spec, I just need to run DaggerTestComponent.builder().build().inject(this)
before each test or spec.Spec
doesn't contain it's type or something...sam
11/03/2021, 2:20 PMclass DaggerExtension : PostInstantiationExtension {
override suspend fun instantiated(spec: Spec): Spec {
val c = Class.forName("Dagger" + spec::class.name) // this would be DaggerMyTest
val m = c.declaredMethods.find { it.name == "builder" ) // get builder() method
val builder = m.invoke(null) as DaggerBuilder
DaggerBuilder.build().inject(spec)
return spec
}
}
dave08
11/03/2021, 2:33 PMClass.forName("Dagger" + spec::class.name)
isn't the spec, it should be Class.forName("Dagger" + componentInterface::class.name)
... say TestComponent
would have DaggerTestComponent
implementation generated that contains a function inject(spec: SomeSpec)
which is the function that I need to run...sam
11/03/2021, 2:33 PM