https://kotlinlang.org logo
Title
h

Håkon Holmstedt

11/16/2021, 12:34 PM
Hi! My team is starting to hurt from long (test)compile times and we are wondering if inheritance could be the culprit. We have an
AbstractBaseTest
class of about 2000 lines that is inherited by many of our tests, and we have read somewhere on the jetbrains blog that large classes can impact compile time. Is it reasonable to think that rewriting the AbstractBaseClass to something concrete that tests can use, rather than inherit, would improve our situation?
p

pniederw

11/16/2021, 2:58 PM
I’d think only if compiling
AbstractBaseTest
itself is the problem.
t

tddmonkey

11/17/2021, 11:39 AM
2000 lines in a base class?! 😮
h

Håkon Holmstedt

11/17/2021, 11:39 AM
Turns out that any change to the
AbstractBaseTest
(even adding an unused, empty function) adds a minute to the
compileTestKotlin
phase of our gradle build, while similar changes to any of the concrete subclasses only adds about a second. So the base class is absolutely our problem… I guess we’ll be looking into a different solution for sharing the setup.
@tddmonkey yeah, its not our proudest thing…
t

tddmonkey

11/17/2021, 11:39 AM
I gotta ask - what is it you’re doing for every test that takes up 2000 lines?
h

Håkon Holmstedt

11/17/2021, 11:42 AM
It does a lot of the heavy lifting of pushing various events around the application to get things into the right state for whatever we are testing. It provides a decent DSL for describing scenarios, and our domain is sadly stupidly complex.
It also provides a bunch of inspectors/visitors to assert the state of our objects after running scenarios.
(and right now, it provides the juiciest target for my next redesign-frenzy)
e

Emil Kantis

11/17/2021, 5:51 PM
why does it need to be in an abstract base class, can't you just use functions?
h

Håkon Holmstedt

11/17/2021, 6:06 PM
"need" is a strong word 😉 It is a base class right now, and it is the accumulation of years of just getting things to work and rarely going back to clean up. That said, it allows us to create most any scenario by simulating external business events, letting us write complex end to end tests fairly easily. Right now, I'm looking at changing it to a concrete class that the actual tests depend on instead of inherit. I guess I should note that this is only a base for our end to end tests. We have a bunch of unit tests that are far less insane
😊 1
t

tddmonkey

11/17/2021, 7:09 PM
You already know what my recommendation is, which is composition
💯 3
c

crummy

11/17/2021, 8:09 PM
regardless of what's best practice, it does surprise me that it slows down the tests so much
h

Håkon Holmstedt

11/17/2021, 8:12 PM
My suspicion right now is that the large base class combined with rather a lot of concrete subclasses that also tend towards being large is causing the problem: every change in the base would trigger a recompile of every subclass, right? I am very far from being a compiler expert, though.
m

Michael Böiers

11/18/2021, 9:57 AM
I don’t think that the base class is compiled more than once, so it itself is probably not causing the long compile time. But if you have a lot of classes extending it in non-obvious ways, I could see how that could slow down compilation of the sub classes. IMHO abstract test base classes are an anti-pattern. Have you considered moving the things this base class does into separate tool classes which can then be used by the tests that actually need them? In my experience these bloated test classes offer so much functionality that any given sub class only uses a small portion of it.
“That said, it allows us to create most any scenario by simulating external business events, letting us write complex end to end tests fairly easily.” @Håkon Holmstedt The price you’re paying for this convenience is not knowing the dependencies of the tests. And the compiler might have a similar problem - for each test it needs to figure out whether it’s “compatible” with the base class.