Skip to main content

Unit Tests in BitDive

This guide shows how BitDive turns real application executions into backend unit tests that you can run with standard tooling. You will record a scenario, pick specific calls, generate a test in the UI, and then run it as regular Maven JUnit tests locally or in CI/CD.

Video Walkthrough

If you prefer text, follow the same flow step by step below.

How BitDive Generates Tests

BitDive does not use AI to generate test code. Instead, it uses deterministic logic from real recorded traces (exact inputs, exact outputs, and the exact interaction graph observed at runtime). It doesn't guess or predict. It records what actually happened and replays it in a controlled environment. If a test fails, it means your behavior changed, not that the test made an incorrect assumption.

Why Use BitDive for Unit Testing?

Traditional testing often involves a trade-off: brittle E2E tests that break with every UI change, or maintainable unit tests that mock away reality. BitDive offers a third way:

  • Zero-Code Automation: You don't write test code; you capture real behavior. This eliminates "code bloat" and the need to maintain thousands of lines of test scripts.
  • "Log-less" Debugging: When a test fails, you don't hunt through logs. You see the exact method, SQL query, or external call that caused the failure, effectively giving you "white box" visibility instantly.
  • Protection against Semantic Drift: BitDive doesn't just check for a 200 OK. It validates that the internal logic (the sequence of calls, the structure of responses) matches the baseline, catching subtle regressions that standard tests miss.

What BitDive Unit Tests Are

A BitDive unit test starts from a real recorded call and becomes a replay plan that is executable as a standard Maven test run. You do not write a new test class for each scenario. Instead, BitDive stores a structured test definition and your project includes a lightweight JUnit harness that loads this definition by identifier, replays the execution in a controlled environment, and verifies that the code behaves as expected.

In practice, this is closer to "method level verification based on a real execution" than to HTTP-only testing. BitDive validates the call chain inside the service and checks methods one by one, using what was captured in the trace. Network protocols are just one of the possible dependency types.

Step 1: Capture Runtime Behavior

Start your microservices application and make sure BitDive is connected. Then open the application UI and execute a small scenario the way a QA engineer or a user would. Click through a few different operations so BitDive captures useful calls.

For example, you might delete a student, delete a teacher, request students for a course, and generate a report. If something fails, such as a 500 error, keep it. Failed calls are valuable because you can immediately inspect the exact method and SQL chain that produced the error and later turn that scenario into a regression test.

Step 2: Inspect Captured Calls in the HeatMap

Open a fresh BitDive workspace. After capturing behavior, the workspace will show the services and dependencies that participated in your actions. You will see the call flow across microservices (Report, Faculty, OpenAI), as well as infrastructure and external dependencies like databases (Postgres) and message brokers (Kafka).

BitDive Microservices Service Map and Heatmap showing captured runtime dependencies

Next, open the HeatMap. It provides a structured view of captured calls grouped per method, with the key metrics attached. When you open a specific call, you can drill down to the full execution flow.

For example, if the teacher deletion request failed with a 500 Internal Server Error, you can drill down to the exact methods and SQL queries to understand where the failure happened.

Analyzing SQL performance and debugging database errors in BitDive Method Tracing

Step 3: Create a Unit Test in the BitDive UI

Go to the Testing tab and create a new test. Give it a name, such as "Unit Test 1", and choose the unit test type. Then select the operations you want to cover from the list of what you have just executed.

Let's pick Update Student and GetStudentsForCourseReport. The "GetStudentsForCourseReport" call is especially interesting because it is fairly complex.

Selecting captured traces in BitDive UI for zero-code unit test creation

For each operation, choose the specific call, meaning the recorded trace. Each call can be opened and inspected. You can see the input arguments, the returned values, and the full execution flow across methods. You can go down to very fine details, including specific DTOs, what is passed between microservices, and which SQL queries are executed against the database.

Detailed trace view in BitDive showing input and output parameters for API calls

Once you have selected the calls for your chosen operations (e.g., the first two calls for "Update Student"), click "Generate Test".

BitDive Unit Test Creation UI for automated regression testing

BitDive will create a test definition that contains the captured inputs, expected outputs, and the recorded interactions required for deterministic replay.

At this point BitDive also prepares the test environment automatically. The goal is not to "mock HTTP", but to recreate the full runtime context so your code can execute deterministically. That includes replacing dependency responses with recorded ones.

Step 4: Run Unit Tests with Maven

Open the target service in your IDE (e.g., the Faculty service), and ensure it is configured to run via BitDive Replay.

In the BitDive UI, copy the generated test identifier. Paste it into your test configuration in the IDE (standard JUnit). If you have multiple tests, you can provide several identifiers separated by commas to run a complete regression set.

Then run tests as you normally would in a Java project, using Maven:

mvn test

Maven JUnit test execution results for automated BitDive unit tests

You may notice a large number of executed tests (e.g., 116 tests) because inside those calls we validate each method, and the call chains can be quite deep.

Step 5: Review Test Results in Your IDE

To see details, run the test directly in your IDE (e.g., IntelliJ IDEA). This allows you to walk through each method and operation using the IDE's test runner to visually compare what was expected versus what actually came back. This applies to all calls and every method.

Reviewing unit test results and deviations in IDE using BitDive Replay

This is the core outcome: deterministic backend unit tests built from real traces, executed with Maven, reviewed like regular developer oriented unit test results, and runnable without hand-written mocks.

Shared Reality for Bug Reporting

One of the biggest benefits is the elimination of "it works on my machine". Because the test is based on a recorded trace, a QA engineer can send a developer a link (or a test ID) that reproduces the exact state of the system at the time of failure. This creates a "shared reality" where developers can fix the bug in minutes rather than spending hours reproducing it.

How It Works Internally

BitDive connects two worlds: runtime tracing and unit test execution. When you click "Generate Test", BitDive builds a replay plan from the recorded trace. It identifies the entrypoint, keeps the input parameters, records the expected outputs, and stores the interaction data needed to replay dependencies in a deterministic way.

On the application side, BitDive Replay provides a JUnit harness. Instead of writing a test method for each scenario, you reference the BitDive test identifier. The harness loads the replay plan, generates JUnit dynamic tests, starts a Spring Boot context in test mode, and executes the entrypoint under replay control.

To keep tests deterministic and safe to run on any machine or in CI, the replay mode starts the application with test oriented configuration. In this mode, the context can allow bean overriding, avoid connecting to real infrastructure unless explicitly configured, and apply overrides based on the replay plan.

Dependency Replay vs HTTP Mocking

It is easy to describe replay using HTTP examples, but that can create the wrong impression. BitDive does not focus on a single protocol. The replay engine uses captured runtime behavior to satisfy dependency calls in the same way the original execution did, regardless of where those calls go.

When your code calls a repository and the database returns rows, the test uses recorded database results instead of hitting a real database. When your code calls another microservice, the test can return the recorded response. If your flow includes messaging or other integrations, the same principle applies.

The key idea is that BitDive unit tests verify internal method behavior, step by step, while dependency interactions are replayed deterministically from the trace. This is how you can validate deep call chains without building and maintaining a fragile mock setup.

Best Practices for Creating Unit Tests from Traces

When you start creating unit tests from traces, prefer calls that are naturally stable. If a call contains noisy values like timestamps, random IDs, or unstable ordering, you can still test it, but you should focus assertions on the meaningful fields and ignore the noise. Complex calls are often the best regression baseline because they cover more logic in a single scenario and reveal subtle integration behaviors early.

Summary

With BitDive, the workflow is straightforward. You execute a scenario to generate traffic, inspect captured calls, select the exact traces you want, generate a unit test from the UI, and run it with mvn test locally or in CI/CD. The key difference is that tests are produced from deterministic replay of real behavior, not from AI-generated guesses, and the whole runtime context is reconstructed automatically so you do not need to create mocks for databases or external services by hand.