I’d like to vote for this feature, it’s I think th...
# kotlintest
w
I’d like to vote for this feature, it’s I think the only that’s missing from classic bdd testing frameworks. Right now it’s a bit awkward to set isolation mode to per-test, and still have to write cleanup code after the last test. The advantage of current approach is we don’t need
lateinit
keyword, while setting stuff from closures will often make it necessary
👍🏾 1
j
@wasyl Can you point to an example of how you do what you described? I’m new to Kotlintest and unclear about the best way to manage and distribute setup and teardown over multiple nested contexts in a Spec. That’s what led me to ask my initial question actually.
s
In kotlintest you can do things with variables like you would in a normal function. Each “test scope” is scoped independently
j
@sam What I’m asking about is, when you have fixture setup at each level of a deeply nested tree of contexts, what is visible to each of these setups? More specifically, what’s the lifespan of the values that are in scope? When I tried this I encountered behavior I didn’t understand. I couldn’t tell what value would be read at a given instant from a variable in a parent context that might be multiple levels up.
s
the scope is like it would be for normal blocks. The lifecycle depends on isolation mode. https://github.com/kotlintest/kotlintest/blob/master/doc/isolation_mode.md I’ll answer your question in more depth this weekend.
j
@sam Ok, thanks!
s
The idea in kotlintest is that you don’t need fixtures. They’re just an artificial construct because of limitations in other frameworks.
In normal code you place variables in scopes dependent on how long you want them to live. Same in KT.
j
Ah, but then how would one do teardown that’s specific to some tests, but not others? The limitation of scopes without fixtures is that you lose the sequential order effect of before-after at the level of specific groups of tests.
s
just put the tear down code after the test block
Copy code
val database = setup()

test("test 1") { 
 ...
}

database.stop()
Copy code
test("outer test") {
  val database = setup()

  test("inner test scope") {
   ...
  }

  database.stop()
}
you can just keep nesting like that
j
Ah, very interesting. I didn’t realize that tests were executed in the order encountered in their parent context, relative to arbitrary statements encountered before and after the test in the same parent context. I’ll try this out. Do you think this already fully covers the Spek functionality I referred to in my origin post?
s
Yes, I think so
but I’ll work through your original post in case there’s missing functionality
test fixtures (imo) are a reaction to the fact other frameworks don’t have the advanced scoping that KT has
j
👍🏽
w
They’re just an artificial construct because of limitations in other frameworks.
At the same time they are quite helpful (imo) in terms of readability. Having setup and cleanup code in one place is a plus for me
s
Happy to investigate adding alternative syntax
j
Just read @wasyl's issue #952.
In KotlinTest there is fun beforeTest(testCase: TestCase) that we can override, but it's global for all test cases in spec, and not scoped. This means we can't access data defined in the context for example.
It's been a while since I used Spek, so I'd need to verify, but I think it supports scoped fixtures.
w
As far as I remember yes, Spek does have scoped fixtures and that was my primary doubt when choosing between the two 🙂