-
-
Notifications
You must be signed in to change notification settings - Fork 705
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
Improve the performance of methods SoftAssertions#assertThat #2563
Comments
Perhaps an option for AssertJ would be to generate the proxies for the known classes during build time. Not sure what kind of an impact this can have on the JAR size of AssertJ. Apart from that not sure if @raphw might have some better ideas for how to improve the performance. Perhaps there are some things that can be done in AssertJ, that we don't know about. |
Are you running single tests? In this case, it takes longer indeed. The "problem" is that Byte Buddy resolves generics and bridges to correctly proxy types. Even if such type information is not present, it is resolved lazily what requires I/O and adds to the total balance. If you run a largish suite, this should not normally be a problem. Have you tried running with |
@raphw Now, if you combine a) and b) with the Mockito overhead and AssertJ overhead, if our test is "unlucky" and ends up being the first test that needs to warm up the proxies, then we are experiencing flaky tests due to the TimeOut issue. Even if we solve a) and remove the JVM forking, with the current timeouts, the firstly executed tests are still flaky while there is technically nothing wrong with them. We tried to brainstorm many ideas, but have come to a conclusion that ideally we need to address the root causes rather than force everyone in the company to apply all kinds of workarounds. The root causes are Some questions we would like to explore:
Thanks for your thoughts. |
Thinking out loud, @filiphr suggestion or code generation could work. We would need to do POCs to validate these approaches. |
Byte Buddy has a build plugin. In theory, you can preproduce classes and use them. This is what I do with Byte Buddy and Mockito on Graal images what is a rather new feature there, but it requires some setup that is costly. In general, though, short running programs such as single test execution, and dynamic code generation do never go well together. Ideally, you'd keep a warmed-up VM ready where assertj and Mockito reuse classes. |
@raphw is there any example I could look at in Byte Buddy or Mockito about the build plugin? |
We also bumped into a similar challenge! I wonder if anyone has found a good solution for it! :) |
Unfortunately, we haven't had enough capacity to look into it so far. I'll add it to the next release scope for a first analysis. |
I'd love to see improvement here because I've had to stop using SoftAssertions in my tests when doing TDD. Even 500ms is too long when the entire set of tests run in under 900ms otherwise. Anything I can do to help? |
Thanks for the offer, @tedyoung! We still didn't have enough time to try out the proposal at #2563 (comment) and #2563 (comment). Would you like to give it a shot? |
Summary
We recently upgraded from AssertJ 3.8.0 to 3.22.0 and we noticed significant slow down in tests using SoftAssertions#assertThat.
I look into it and found that AssertJ switched from cglib to ByteBuddy in 3.9.1.
I did some simple performance corporation between version and found that proxy generation is ~4x slower compare to AssertJ 3.8.0. with cglib. Speed difference is quite noticeable especially on first running test. TypeCache in SoftProxies is kinda helping, but only tests running after type was already cached.
I also compare times from AssertJ 3.22.0 to Mockito 3.2.4 (which is quite old, but it's too using ByteBuddy to generate sub-classes) and found that execution times for generating classes are almost identical.
This slowdown make SoftAssertions#assertThat unsuitable for some of our tests, as they must run under 2s + it makes harder to predict actual execution time of whole test. We found workaround in SoftAssertions#check(() -> assertThat) but this syntax can be harder to read in longer tests so we would prefer to use SoftAssertions#assertThat as it's more natural.
I want to ask you if you could please look into this problem and found if there is any space to improvement?
I understand that there isn't probably any space on ByteBuddy side for improvements, but maybe there could be done something on ours?
Maybe change some strategy or use ByteBuddy to generate class from interface (not actual class) and delegate calls to real object (but that would require create interfaces for each Assert class and I'm not sure if it would be possible due generic + if such change wouldn't result if worse runtime performance).
This problem can be also environment problem and sub-class generation is much faster on newer versions of JDK (but I have doubts about that, I experienced similar problems on up-to-date versions of JDK 11 too).
Testing environment
java version "11.0.12" 2021-07-20 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.12+8-LTS-237)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.12+8-LTS-237, mixed mode)
Tests were performed in Intellij Idea 2020.2.4
AssertJ performance comparison
Used tests:
Results:
AssertJ 3.8.0
AssertJ 3.22.0
Mockito 3.2.4
The text was updated successfully, but these errors were encountered: