To maintain developer productivity in automated testing, it's essential to prioritize tests based on factors like size and duration, as demonstrated by Google's guild system. Smoke tests can provide a quick sense of project health and should be prioritized.
Interpreting test results can be overwhelming, especially when dealing with a high volume of test cases. Teams adopt various strategies, such as taming, masking, or ignoring flakiness, to handle noisy test results effectively.
Troubleshooting failures requires reproducibility, but intermittent failures, environment variability, non-deterministic behavior, complex dependencies, and data-related issues can make this challenging. Preserving test environments is vital for thorough examination and debugging.
Leveraging AI and data-driven approaches, like Launchable, can help filter out noise from unhealthy tests, provide clarity on software issues, and automate grouping related failures, ultimately boosting developer productivity in automated testing.
Watch the full "Navigating the firehose of test failures" webinar here
Developer productivity is a critical factor in delivering high-quality code. However, this often-overlooked aspect of DevOps can be a significant challenge, particularly when it comes to automated testing.
But running automated tests is just the tip of the iceberg when it comes to developer productivity. The real challenge lies in what happens next, commonly referred to as the triage process. When a test fails, it's not just about identifying the problem; it's about understanding how it impacts the functionality of the system.
But how do you ensure that your tests run smoothly and don't slow down your development process? Prioritization becomes critical in this context.
You can't afford to run every test for every code change. Here, prioritization can mean categorizing tests by size and duration, a strategy employed by Google's build system. Smoke tests, which provide a quick sense of the project's health, become invaluable in this scenario.
When you have numerous test cases running frequently, it's easy to get overwhelmed by the sheer volume of results. Interpreting test results can be overwhelming with the noise created by the volume of test cases running.
Let's take the example of the Jenkins project, a widely-used automation server. One of their integration acceptance tests started generating an overwhelming volume of results. This situation led to the test being ignored. But was that the best option? How do teams tackle flaky tests?
Teams often adopt one of three approaches to deal with flakiness issues:
Taming Flakiness: While it's hard to eliminate flakiness entirely, focusing on the most problematic failures helps keep them in check.
Masking Flakiness: Some teams exclude flaky tests to reduce noise, although this may lead to longer fix times.
Ignoring Flakiness: In extreme cases, teams run flaky tests but disregard their results for certain purposes, balancing tests without letting noise disrupt integrations.
Efforts are made to quantify flakiness's impact on test feeds, helping teams prioritize the most impactful issues. Dropbox, for instance, reruns noisy tests before human review, determining if they consistently fail or are simply flaky. Flaky tests are quarantined to prevent disruption to development.
While Dropbox can afford advanced solutions, the goal is to make these systems widely available for most teams. Usable systems should be accessible without the need to build everything from scratch.
To deal with noise, teams often use the technique of snoozing failures. This involves acknowledging and excluding them until resolved. Annotating tests with references to issues can help track their status.
Consider a large-scale financial software application where multiple microservices interact. When a test fails, it's not always obvious which part of the system is responsible. Investigating such failures can involve digging through logs and distributed systems. While automatic tools like Zipkin and Jaeger can help gather information, many teams rely on manual log analysis to unravel the complexities.
Troubleshooting failures can be a complex and time-consuming process. It often involves determining whether the issue lies in application code, test code, or environmental changes.
Imagine you're working on a healthcare software system where patient data must remain secure. If a test fails, it's imperative to reproduce the issue in a controlled environment to ensure patient safety. Preserving test environments for a set period becomes effective in allowing developers to examine failures thoroughly. However, reproducing test failures is often easier said than done.
Common hurdles teams face when attempting to recreate failures include:
Intermittent Failures: Some test failures occur sporadically, rendering them exceptionally challenging to reproduce. A test might pass during subsequent runs, leaving the team bewildered regarding the underlying issue's cause.
Environment Variability: Test environments seldom mirror production environments identically. Disparities in hardware, software, configurations, and data can engender failures that exclusively surface under specific circumstances.
Non-Deterministic Behavior: Certain failures are the result of non-deterministic software behavior, making it arduous to predict when they will transpire. Issues such as race conditions, thread synchronization anomalies, and timing-related bugs fall under this category.
Complex Dependencies: Contemporary software relies heavily on diverse external services, APIs, databases, and third-party libraries. Failures within any of these dependencies can incite test failures within the primary application.
Data-Related Failures: In numerous instances, test failures are intertwined with the data utilized in the testing process. Corrupted, incomplete, or inconsistent test data can lead to failures that are challenging to isolate and understand.
Preserving a test environment allows teams to replicate the exact conditions under which a failure occurred. This is invaluable for debugging and pinpointing the root cause.
Once test failures are identified, passing information to the appropriate team for fixes is crucial.
In a larger organization, coordinating test failure fixes can be a daunting task. Consider a scenario where a global e-commerce platform faces a critical test failure just before a major sales event. In this case, achieving uniformity across teams and ensuring timely fixes is essential. Streamlining the process involves establishing clear prioritization criteria in advance, such as the impact on core users or the percentage of affected users.
The Future of Developer Productivity: Leveraging AI and Data-Driven Approaches for Intelligent Triage
Help your team find calm amidst the chaos and ship with confidence. Launchable optimizes your automated software testing by:
Filtering away the noise from your unhealthy tests to find and focus on what truly matters.
Driving instant clarity on underlying software issues raised by test failures.
Keeping every team member informed, when it really matters.
Predictive test selection ensures you run the tests that are likely to find failures first. Quickly find and verify test issues – save time, reduce costs, and ensure every test run counts. With AI-powered Insights, flag and quantify the friction caused by unhealthy tests helping teams to prioritize issues that matter.
Launchable empowers teams to re-imagine issue diagnosis by automatically grouping related failures. Your Gen-AI copilot summarizes long comprehensive error logs for faster comprehension. Swiftly pinpoint root causes while reducing testing noise with contextualized and personalized notifications for developers to accelerate your software delivery timeline.