-
-
Notifications
You must be signed in to change notification settings - Fork 757
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Test performance improvements #2921
Conversation
Codecov Report
@@ Coverage Diff @@
## master #2921 +/- ##
============================================
+ Coverage 80.22% 80.23% +0.01%
+ Complexity 2449 2448 -1
============================================
Files 421 421
Lines 7408 7402 -6
Branches 1356 1352 -4
============================================
- Hits 5943 5939 -4
Misses 764 764
+ Partials 701 699 -2
Continue to review full report at Codecov.
|
There are 2 hard problems in computer science: threads, naming things, and off-by-1 errors. |
Did some profiling and spek is fast enough. Classgraph single-threaded works too. |
Hey! Out of curiosity, what does |
One thing weird I found is when running |
Changing this made the discrepancy smaller from 5s (alone) -> 7s (all tests) It was declared like this before: val finding = mockk<Finding>()
every { finding.id }.returns("LongParameterList")
every { finding.signature }.returns("Signature")
val result = TestDetektion(finding) So it was building the mock during discovery phase. |
One improvement I could suggest is avoid doing heavy stuff in the group scopes, use a combination of fixtures (beforeEachTest, beforeEachGroup, etc ..) and memoized to delay calculation values used during the execution phase. |
I've also made a change to fun Root.setupKotlinEnvironment() {
val wrapper by memoized(CachingMode.SCOPE, { createEnvironment() }, { it.dispose() } )
@Suppress("UNUSED_VARIABLE") // name is used for delegation
val env: KotlinCoreEnvironment by memoized(CachingMode.EACH_GROUP) { wrapper.env }
}
|
After a couple of testing from this branch, the biggest difference I can see is when making sure nothing heavy is calculated in the discovery phase. I've tried making cg scanning and execution sequential but the difference are negligible 1-2 seconds. [1] I made changes to your test (2m 9.625s): https://scans.gradle.com/s/hvit4fbjj54j6/tests?collapse-all vs [2] No changes (2m 37.258s): https://scans.gradle.com/s/k3cwnp74ersju/tests?collapse-all From what I can see the individual test timings in Gradle's scan doesn't account for discovery time - but just execution time. |
@raniejade thank you very much for taking the time to help us out! I also removed the coroutine usage but the time between starting the test task and executing the tests is nearly the same (1-2s as you mentioned). So the only thing we can do is to stop introducing new modules which need the kotlin compiler or mockk :/. |
I think if we can just make sure that no heavy initialization happens in the discovery phase, will help improve discovery. There are probably other areas in your tests that are doing some initialization in the discovery phase, fixing them might help improve test speeds. |
Awesome stuff!! |
Yes, it is definitely the way to move heavy setup code from discovery to the execution phase. Edit: modules like |
Findings:
module report-txt without thedetekt-test
dependency starts instantly!!!does this mean spek tries to discover to much? still running through all jars/the whole classpath??have we setup the KtTestCompiler and ScriptEngine wrongly??both classes are only used in methods and Kotlinobject
s guarantees us singletonsI've tried to remove theobject
declarations and using customlazy
inits -> no improvementsReferences: