How to fix flaky tests

Flaky Tests

Aug 30, 2023

Software development is a complex process that involves writing and testing code to ensure its functionality. Flaky tests, however, can be a real roadblock in this development process. They can cause a lot of time-consuming reruns and debugging, as they produce inconsistent test results. This can result in failed tests, making it challenging for a software engineer to maintain an efficient workflow. In this guide, we'll discuss how to find and fix flaky tests in your test suite.

The Problem with Flaky Tests

Flaky tests are those that exhibit non-deterministic behavior. These are tests that yield different outcomes even when there are no changes in the code or test environment. They are problematic because they introduce uncertainty into the test results, which can interfere with the continuous integration (CI) and CD pipeline workflows. They can cause unnecessary test failures, leading to time-consuming debugging and rerunning of tests. Test flakiness can be introduced by various dependencies and other factors like concurrency, asynchronous code, and order dependency among others.

Step 1: Commit to Fixing the Problem Right Away!

The first step to deal with flaky tests is to commit to fixing the issue promptly. When a test fails, it might be tempting to simply rerun it until it passes. However, this approach doesn't address the root cause of the flakiness and can lead to more failed tests down the line. It is essential to prioritize identifying and fixing flaky tests to maintain the reliability of your test suite and to ensure the accuracy of test results.

Step 2: Find the Flaky Tests in Your Suite

The next step is identifying the flaky tests in your test suite. BuildPulse offers a comprehensive platform to find flaky tests, measure their impact on the product and the engineering team, and alert stakeholders of any issues while they’re still manageable.

You can also consider some other techniques:

Saving Debugging Information

Every time a test fails, make sure to save all relevant debugging information. This includes logs, screenshots, and any other data that could help diagnose the issue. This data can be invaluable when trying to find the root cause of the flakiness.

SSH Debugging

Some testing platforms allow for SSH debugging, which can provide a live look into the test environment when a test fails. This can help uncover hidden causes of flakiness.

A Picture Says More Than a Thousand Words

Whenever possible, use visual aids like screenshots and screen recordings. These can help illustrate what's happening at the frontend when a test fails.

Configuring Reports in the Pipeline

Configure your CI pipeline to generate detailed test reports whenever a test run completes. These reports can help identify patterns and trends related to test flakiness. Integration with platforms like GitHub can further streamline this process.

Step 3: Documenting Flaky Tests

Keeping a detailed record of flaky tests is critical. Document every instance of a flaky test, including when it occurred, the test environment, any error messages, and any attempted fixes. This documentation can be helpful for future reference and can assist in identifying common causes of flakiness.

Step 4: Determining the Cause and Fixing the Test

Once you've identified and documented the flaky tests, the next step is to determine the cause and fix the issue. Several common causes can lead to test flakiness:

Environmental Differences

Flakiness can often be attributed to differences in test environments. Make sure that the test environment closely mirrors the production environment to reduce the risk of environmental flakiness.

Non-deterministic Code

If your code relies on random factors or specific timing, it can lead to flaky tests. Try to avoid non-deterministic code whenever possible.

Asynchronous Wait

Flaky tests can occur if your test cases do not properly handle asynchronous API calls. Implementing appropriate wait times or callbacks can help alleviate this issue.

Concurrency

Concurrency issues can also cause flakiness. If your tests are not properly synchronized, they can interfere with each other and lead to flaky outcomes.

Order Dependency

Tests should be independent and not rely on the order in which they are run. If test order is causing flakiness, consider refactoring your tests to eliminate these dependencies.

Improper Assumptions

Sometimes, tests make improper assumptions about the state of the system, leading to flaky outcomes. Review your test cases to ensure they accurately represent the expected functionality.

Fixing the Test

Once the root cause of the flakiness is determined, the final step is to fix the test. This can involve refactoring the test code, adjusting timeouts, changing the order of test execution, and so on. Utilize your testing framework and implement best practices for writing reliable test code.

Conclusion

Flaky tests can pose a significant challenge in software development, leading to inefficient workflows and unreliable test results. However, by committing to addressing the issue, identifying and documenting flaky tests, determining the cause, and implementing necessary changes, flaky tests can be effectively managed. Leveraging tools for test detection and reporting, like Slack notifications for test failures, can help maintain a reliable test suite, ensuring the quality of your end-to-end testing, unit tests, and regression testing. Remember that maintaining test reliability is a continuous process and plays a crucial role in successful software development.

FAQ

Does BuildPulse replace my current CI system?

No.

We use GitHub Actions / CircleCI / Semaphore CI self-hosted functionality to run your builds on our infrastructure.

Other than faster builds, there are no changes to your developers' workflows - you can continue using your CI system as-is.

How is BuildPulse faster than GitHub Actions hosted runners?

We use GitHub’s self-hosted functionality to run your builds on our infrastructure with latest generation + high single-core performance CPUs, also then further optimized for CI-type workloads. We’ve also tuned our VMs and block storage devices, increasing baseline performance while also cutting costs in half.

We also provide a toolkit to further speed up your pipelines, which includes ultra fast remote docker builders, docker layer caching, dependency caching, and more. With all of these improvements, we’ve seen 2x+ performance improvements in build times.

Can I use BuildPulse with other CI providers than GitHub Actions?

Yes! BuildPulse Runners will run jobs for CircleCI, SemaphoreCI - GitLab coming soon.

We aim to support all popular CI systems. If you're using one that's not listed, please contact support@buildpulse.io!

Is there a free trial available?

Yes, you can book a meeting here!

How do you secure my builds?

BuildPulse runs each job in a network- and compute- isolated environment with ephemeral VMs that leave behind a clean state after every run.

Do you support Mac and Windows runners?

This is on our roadmap! Email us at hello@buildpulse.io, or book a demo here!

Is BuildPulse SOC 2 compliant?

Yes, BuildPulse is SOC 2 Type 2 compliant.

Contact us at hello@buildpulse.io for more information.

How are BuildPulse Runners priced?

BuildPulse Runners charges on a per-second basis, which depend on the runner-type used. See our pricing page for more details.

How long does implementation/integration with BuildPulse take?

The minimum implementation involves 2 steps: Signing up for BuildPulse, and changing 1 in your GitHub Actions yaml file.

If you're using Semaphore CI or Circle CI, it's a 4 line change. See our Getting Started guide for more details.

Does BuildPulse replace my current CI system?

No.

We use GitHub Actions / CircleCI / Semaphore CI self-hosted functionality to run your builds on our infrastructure.

Other than faster builds, there are no changes to your developers' workflows - you can continue using your CI system as-is.

How is BuildPulse faster than GitHub Actions hosted runners?

We use GitHub’s self-hosted functionality to run your builds on our infrastructure with latest generation + high single-core performance CPUs, also then further optimized for CI-type workloads. We’ve also tuned our VMs and block storage devices, increasing baseline performance while also cutting costs in half.

We also provide a toolkit to further speed up your pipelines, which includes ultra fast remote docker builders, docker layer caching, dependency caching, and more. With all of these improvements, we’ve seen 2x+ performance improvements in build times.

Can I use BuildPulse with other CI providers than GitHub Actions?

Yes! BuildPulse Runners will run jobs for CircleCI, SemaphoreCI - GitLab coming soon.

We aim to support all popular CI systems. If you're using one that's not listed, please contact support@buildpulse.io!

Is there a free trial available?

Yes, you can book a meeting here!

How do you secure my builds?

BuildPulse runs each job in a network- and compute- isolated environment with ephemeral VMs that leave behind a clean state after every run.

Do you support Mac and Windows runners?

This is on our roadmap! Email us at hello@buildpulse.io, or book a demo here!

Is BuildPulse SOC 2 compliant?

Yes, BuildPulse is SOC 2 Type 2 compliant.

Contact us at hello@buildpulse.io for more information.

How are BuildPulse Runners priced?

BuildPulse Runners charges on a per-second basis, which depend on the runner-type used. See our pricing page for more details.

How long does implementation/integration with BuildPulse take?

The minimum implementation involves 2 steps: Signing up for BuildPulse, and changing 1 in your GitHub Actions yaml file.

If you're using Semaphore CI or Circle CI, it's a 4 line change. See our Getting Started guide for more details.

Does BuildPulse replace my current CI system?

No.

We use GitHub Actions / CircleCI / Semaphore CI self-hosted functionality to run your builds on our infrastructure.

Other than faster builds, there are no changes to your developers' workflows - you can continue using your CI system as-is.

How is BuildPulse faster than GitHub Actions hosted runners?

We use GitHub’s self-hosted functionality to run your builds on our infrastructure with latest generation + high single-core performance CPUs, also then further optimized for CI-type workloads. We’ve also tuned our VMs and block storage devices, increasing baseline performance while also cutting costs in half.

We also provide a toolkit to further speed up your pipelines, which includes ultra fast remote docker builders, docker layer caching, dependency caching, and more. With all of these improvements, we’ve seen 2x+ performance improvements in build times.

Can I use BuildPulse with other CI providers than GitHub Actions?

Yes! BuildPulse Runners will run jobs for CircleCI, SemaphoreCI - GitLab coming soon.

We aim to support all popular CI systems. If you're using one that's not listed, please contact support@buildpulse.io!

Is there a free trial available?

Yes, you can book a meeting here!

How do you secure my builds?

BuildPulse runs each job in a network- and compute- isolated environment with ephemeral VMs that leave behind a clean state after every run.

Do you support Mac and Windows runners?

This is on our roadmap! Email us at hello@buildpulse.io, or book a demo here!

Is BuildPulse SOC 2 compliant?

Yes, BuildPulse is SOC 2 Type 2 compliant.

Contact us at hello@buildpulse.io for more information.

How are BuildPulse Runners priced?

BuildPulse Runners charges on a per-second basis, which depend on the runner-type used. See our pricing page for more details.

How long does implementation/integration with BuildPulse take?

The minimum implementation involves 2 steps: Signing up for BuildPulse, and changing 1 in your GitHub Actions yaml file.

If you're using Semaphore CI or Circle CI, it's a 4 line change. See our Getting Started guide for more details.

Ready for Takeoff?

Ready for Takeoff?

Ready for Takeoff?