A few days ago I've stumbled upon a blog post "Modern Best Practices for Testing in Java" ( https://phauer.com/2019/modern-best-practices-testing-java/) and learned a lot of new things from it.
In a lot of cases, how testing is done in Druid goes against these best practices: - "Given, When, Then" structure: in Druid, rarely followed or clarified via blank lines. - Use the Prefixes “actual*” and “expected*: not in Druid, usually it's something1 / something2 and what is expected and what is actual is unclear (and sometimes confused in assert() args) - Heavily Use Helper Functions: used sometimes in Druid, but by far not enough, in my perception - Don’t Extend Existing Tests To “Just Test One More Tiny Thing: not everywhere, but in a lot of places this practice is abused in Druid tests - Insert Test Data Right In The Test Method: test data is often inserted in @Before in Druid - Favor Composition Over Inheritance: there are some hierarchies in Druid - Don’t Write Too Much Logic: Druid tests feel like *all* boilerplate/noise/scaffolding logic - Don’t Use In-Memory Databases For Tests: Druid does toy database Derby for tests :) - Use AssertJ: Druid doesn't use AssertJ (I've just added AssertJ to dependencies in https://github.com/apache/incubator-druid/pull/8564 in one module) - Use JUnit5: ¯\_(ツ)_/¯ - Mock Remote Service: in Druid, we don't use OkHttp's MockWebServer - Use Awaitility for Asserting Asynchronous Code: in Druid, we use ad-hoc while loops with sleep(10), sleep(100), etc. - Separate Asynchronous Execution and Actual Logic: I think, this is one of the most important points. In Druid, in almost all cases, execution management (thread pools), dependency injection (and dependencies in general), and the "core" logic are alloyed in a single class. This makes testing the core logic very painful with a lot of mocking and setup ceremony, breaking frequently. Following the Humble Object pattern ( http://xunitpatterns.com/Humble%20Object.html) would make writing *and supporting* much less laborious. These things cannot be fixed in one day because test code has a lot of inertia, but I believe to improve developer productivity all active Druid developers should start using most of these practices in all new tests being written, demand other contributors align their tests with these practices in code reviews, and take some time to think about strategic ways to refactor a bulk of existing tests with little effort (semi-automatically) that can at the same time improve their quality even by a little. In my experience, wrestling with tests is a huge (often the biggest) part of changing existing code in Druid, so we pay a huge productivity tax by not paying enough attention to the quality of the test codebase.