Transform Java Code-Level Testing With Automation & AI
By Nathan Jakubiak
November 8, 2023
11 min read
Is your Java development team looking for ways to optimize testing practices and reduce the overhead of code-level testing activities? Read on to uncover how to leverage automation and AI to deliver higher quality code, increase development productivity, and accelerate time to market.
Jump to Section
The most effective approach to attain software quality is to implement a practice of quality and security by design early in the development process. This means that code quality and security postures are determined in the earliest stages and implemented as a best practice as the code is being developed.
In the beginning phases, together with creating and executing unit tests in regression testing, the best practices ensure the code base is reliable, secure, of high quality, and release-ready. However, these testing processes can impact code development productivity due to the engineering time and overhead costs they require. Development teams often struggle with finding a balance between their code development activities and the time needed to test and validate for quality, security, and reliability.
With the advancement of the use of artificial intelligence (AI) in software testing, the overhead cost for development-centric testing practices can be greatly diminished, enabling teams to accelerate and optimize their activities and maintain or even increase their level of code productivity.
Benefits of Performing Static Analysis and Unit Testing Early
Static analysis is often considered low-hanging fruit for development teams when it comes to ensuring code quality. That’s because it offers high benefits with little overhead to the development process.
On the other hand, unit testing practices tend to come with a high price tag in engineering hours needed to create and maintain unit test suites. However, both types of early code-level testing are crucial to creating a foundation for quality in software programs and offer immense benefits that outweigh the costs.
Common benefits of implementing static analysis and unit testing include the following.
- Early bug detection equals cost savings. Code-level testing helps identify and address bugs and defects in the software at an early stage of development, reducing the cost and effort required for debugging and fixing issues later in the development cycle or production. Catching defects in their earliest stages reduces the disruptive detective work that is required for development when a late-stage defect is found. When developers must stop writing new code to analyze code written days or sometimes weeks before to determine the root cause of a defect found by their QA team, it impacts and slows down their development velocity. Code-level testing helps reduce the cost of software development, defect remediation, and maintenance.
- Improved code quality. Testing at the early stages of development helps to hold developers accountable and encourages developers to write cleaner, more modular, and maintainable code. This leads to better software architecture, faster attainment of code coverage requirements, easier alignment to compliance requirements, and adherence to coding standards and design patterns.
- Regression testing. Code-level tests ensure that existing functionality remains intact as new code is added or modified. This helps prevent regression bugs, where changes in one part of the code inadvertently break other parts. By implementing an effective unit testing practice, development teams can execute their suite of unit tests every time they have made significant changes or additions to their code base and find issues before they become costly to remediate in the later stages of development.
- Confidence in code changes. Developers can make changes and add new features with confidence, knowing that their code-level regression test suites and static analysis code scans will alert them to any issues they introduce.
- Faster debugging. When a code-level test fails, it pinpoints the specific location and nature of the problem, making it easier and quicker to identify and resolve issues.
The Impact of AI on Early Code Development and Validation
AI and ML technologies have proven to provide immense benefits to development teams in the optimization and acceleration of testing activities, allowing teams to reduce the overhead associated with static analysis and unit testing practices. To discuss the specific benefits of AI and ML for quality assurance and testing, we need to first break down the challenges associated with these testing activities that result in slowdowns in development velocity and high overhead costs.
Static Analysis Challenges in Focus
Static analysis provides huge benefits, increasing the quality, security, and reliability of software with little disruption to code development. Static analysis can be integrated into the early code development process, enabling developers to run static code analysis scans in their IDEs so that defects can be found as they are written and remediated before they are introduced to the larger code base.
Static analysis can also be integrated into CI/CD pipelines, enabling automatic code scans after every code commit to source control. This allows development teams to easily and automatically check their code behind the scenes for defects, memory leaks, maintainability issues, and compliance requirements.
It’s an easy best practice with low overhead costs. However, static analysis does have some challenges associated with it that can disrupt developers and impact productivity. Parasoft Jtest is designed to mitigate those challenges and help teams optimize their static analysis workflows for a better developer experience and a faster remediation process.
Reducing Noisy Static Analysis Findings
While it’s best to take the quality and security built-in approach and bake static analysis into your code development process and workflow from the very start, many development teams adopt static analysis when code development is well on its way.
Depending on the rule set and the size of the code base, the static analysis solution can produce a huge number of findings or rule violations. For new teams adopting static analysis, running a code scan and getting back thousands of results can be overwhelming, dejecting, and confusing, which can impact the adoption of static analysis tools.
Knowing What to Prioritize
When static analysis results are returned to development teams, understanding what to prioritize in the static analysis findings can be challenging. Many tools come with severity levels associated with each static analysis rule, but at the end of the day, violation prioritization does also come down to the specific code base, the location of the violation, the type of application, and the consumer of the software.
While static analysis rule severity categorizations can give some guidelines to follow, every application is different, resulting in different specific requirements when it comes to code guidelines. Understanding what violations are the top priority to target for remediation based on the specific needs of your application can be challenging.
Understanding Compliance Requirements
Many development teams adopt static analysis due to industry-specific or security requirements. While static analysis solutions often have documentation attached to each rule explaining its importance to specific standards, understanding how to fix the code can be challenging and time-consuming. Not everyone is an extremely proficient developer, and even those who are may find specific rules associated with security or coding standards challenging to follow and difficult to fix when a violation is found.
How AI Optimizes Static Analysis Processes
Parasoft’s Java developer productivity solution, Jtest, is usually packaged with Parasoft DTP for reporting and analytics. DTP is more than a reporting and analytics platform and provides teams with the following benefits:
- Code coverage analysis across the application
- Actionable insights with build-to-build comparisons
- Change analysis
- Static analysis violations tracking
- Compliance reporting capabilities
Related to AI and static analysis, DTP provides incredible benefits to development teams by helping them to identify what violations are most important to their application, assessing the root cause of violations, assigning the most proficient staff members to address the violations, and accelerating the remediation process.
Focuses on High-Priority Findings
Jtest static analysis can be integrated with CI/CD pipelines that then publish static analysis results to Parasoft DTP for reporting and trends analysis. DTP offers ML-based widgets that display classification results based on past user triage actions in DTP. As certain violations are prioritized and others suppressed or ignored from build to build, the ML AI under the hood analyzes these decisions, storing this historical data for future prioritization.
The AI learns from these triage actions and is then able to make recommendations on how to prioritize other static analysis findings. When running static analysis results with noisy violation reporting, having a way to easily classify findings based on the probability of the violation being fixed or ignored can make a big difference in accelerating the remediation process and reducing the burden on development teams.
Clusters Violations by Root Cause Analysis
DTP’s algorithms analyze the root cause of static analysis violations and group related violations together. This allows development managers to assign a cluster of static analysis violations to one developer who will fix the code addressing all the violations at once. This streamlines remediation and reduces work duplication across the development team.
Assigns Violations by Developer Experience
DTP’s ML analyzes build-to-build and triage trends to optimize the overall remediation process. When code scans are published to DTP, quality tasks are created for each violation and automatically assigned to the developer who last touched that line of code.
DTP’s AI also analyzes past triage activities and takes notice of what types of violations specific developers tend to remediate. When assigning violations back for remediation, management is provided with actionable recommendations on what violations to assign to specific developers based on what violations they have remediated in the past.
Fixes Static Analysis Violations With Generative AI
Jtest offers integration with the LLM providers OpenAI and Azure OpenAI to streamline violation remediation with AI-generated fixes. When a violation is found, the developer can select the violation in their development IDE and request an AI-generated fix.
AI will analyze the rule, the violation, and the impacted lines of code and generate a fix for the developer’s review along with analysis of the violation in the context of that specific code. From there the developer can easily implement the fix within their code base. This accelerates the remediation process and enables less proficient developers to fix the code more easily and grow their expertise by learning from the AI-recommended fix.
Unit Testing Challenges in Focus
Unit testing is a fundamental best practice in software development. A solid foundation of unit tests is an effective way to ensure high-quality software and shift left in the detection of defects, enabling remediation during the earliest and least costly stage of the development life cycle. However, implementing a unit testing practice and enforcing adherence to a specific code coverage target requires additional engineering hours for testing activities.
With an average 40% overhead for development organizations, unit testing has a costly price tag. However, with the recent advancements in AI, software development teams can reduce the overhead costs associated with unit testing activities and attain the quality benefits a solid unit test foundation provides.
Unit testing, while incredibly valuable to the health, quality, and reliability of software, comes with its set of challenges and cultural barriers development teams must overcome. Some of the common challenges that are often barriers to successful unit testing practices follow.
At the end of the day, developers want to spend their time writing new code instead of creating and maintaining test cases to validate the code that they just wrote. When the code is more complex, the time it takes to write the test cases also increases.
Isolating the Code Under Test
Ensuring that unit tests are isolated from external dependencies, such as databases, external services, or the file system is crucial. Mocking and stubbing these dependencies takes technical knowledge and is time-consuming. It often requires an understanding of mocking frameworks like Mockito. If the code isn’t properly isolated, testing results can be inaccurate.
Once the test is created, developers still need to maintain that test for regression testing purposes. Test maintenance can be a tedious task. When code has been changed, test cases need to be modified to support the changes and the unit testing suite needs to be re-executed to ensure that the modifications to the code base have not broken existing functionality. Keeping regression test suites clean and maintained is a necessary step to ensure code changes have not broken existing functionality.
Unit Test Code Coverage
Some organizations enforce the attainment of a specific code coverage level to gauge a level of release readiness. 80% line code coverage tends to be a commonly accepted and enforced metric in commercial software. Achieving comprehensive test coverage means testing all code paths and edge cases, which can be challenging. Teams often spend lengthy engineering hours chasing their code coverage metric.
A term often used to describe old code that’s not been written to be easily maintainable or to meet modern quality and security expectations. Often, legacy code has been primarily manually tested, the testing was done sporadically, or the test cases are all in old frameworks that may no longer be relevant. When legacy programs are targeted for either refactoring or modernization, it’s important to create a unit testing suite for regression testing to ensure that the code modifications made by the development team do not break existing functionality. However, when the code has not been written following best practices, is not easily maintainable, or is overly complex, the creation of unit tests becomes even more challenging and time-consuming for the development team.
Resistance to Testing
As unit testing is time-consuming by nature, development organizations often juggle the choice of allocating time for the creation and maintenance of test cases versus focusing on creating new code and increasing their development productivity. Organizations that sacrifice unit testing for a faster time to market are gambling with the increased risk of bugs in production.
How AI Reduces Unit Testing Overhead
Parasoft recognized early on the power that AI and machine learning (ML) technologies can have on reducing the time spent on test case creation and maintenance across the entirety of the testing pyramid. Jtest Unit Test Assistant for Java programs was one of the first AI-powered capabilities launched in the Parasoft Continuous Quality Platform.
Jtest’s AI capabilities enable development teams to rapidly generate a unit test suite that covers up to 60% of the code or more and then further augment test cases to drive additional coverage, quickly stub and mock dependencies, easily add assertions, parameterize test cases, and clone or mutate existing test cases.
Additionally, users can integrate Jtest with their OpenAI or Azure OpenAI accounts and leverage generative AI technology to customize test cases in very specific ways outlined by the developer. Jtest’s implementation of AI helps developers quickly and easily create effective, meaningful test cases customized to the specific requirements of the application while reducing the overhead associated with unit testing activities.
Jtest’s AI benefits developers in the following ways.
- Accelerates unit test creation. As new code is written, best practices dictate the creation of unit tests in parallel with development. Jtest’s Unit Test Assistant enables developers to quickly generate meaningful individual test cases in parallel with code development. Tests can be easily augmented and customized with Unit Test Assistant’s guided and actionable recommendations on how to mock or stub dependencies, add assertions for regression control, or modify the test to drive higher levels of code coverage. Developers can then further augment test cases by using the generative AI LLM integration to customize the test in specific ways dictated by the user’s natural-language prompts. Parasoft’s AI implementation in unit testing practices has been proven to accelerate unit test creation by up to 2x.
- Maintains test cases. Once the unit tests are created, they must be maintained so that they can be continuously used for regression testing. When changes are made to the code base, test cases must be updated to support the changes. Jtest accelerates maintenance steps by analyzing the test during runtime and providing the developer with recommendations on how to update the test case to increase its stability. With Parasoft’s new generative AI features, developers can ask the AI to refactor the test case based on their descriptions of the changes they would like to make. This enables the test case to be more maintainable in the long run.
- Modernizes legacy test cases. With the new generative AI capabilities of Jtest, development teams can easily refactor existing test cases to update them to modern frameworks. For example, if a code base has not been touched for a few years and a new team has been brought in to modernize the application, utilizing the existing test cases for regression control is very helpful. However, the test cases may have been written in an old and outdated format, so engineering hours must be spent on refactoring the test cases to migrate them to modern frameworks. With Jtest’s generative AI capabilities, the developer can easily tell the AI the specifics of how the test case should be refactored and streamline the modernization process.
- Accelerates test feedback. When the unit test suite is large and comprised of thousands of test cases, executing the test suite can take a long time, so developers are often delayed in their debugging and test case maintenance activities as they wait for feedback from their test executions. Test impact analysis, a core component of Parasoft Jtest as well as a component that is integrated across the Parasoft Continuous Quality Platform, enables development and testing teams to run just the test cases impacted by code changes, reducing the size of the test suite that needs to be executed and accelerating the feedback loop.
With the benefits that AI provides, development teams can easily accelerate their unit testing practices and reduce overhead costs by mitigating challenges, automating time-consuming tasks, and enjoying the benefits of software quality that a solid unit test foundation provides.
Optimize Java Software Testing & Reduce Code-Level Testing Overhead
Parasoft Jtest is a powerful solution for development teams looking to optimize their testing practices and reduce the overhead of code-level testing activities. Overall, it provides developers with a positive experience when it comes to testing, enabling them to easily and quickly create, maintain, and execute test cases, as well as run static analysis and address reported violations so that they can spend more time focusing on new code development.
AI optimizes testing and quality-centric practices so that teams can deliver higher quality code, increase their development productivity, accelerate time to market, and release with higher levels of confidence.
Experience Parasoft Jtest’s AI capabilities firsthand with the 14-day free trial!
Contributing author: Jamie Motheral