<!-- go/cmark -->

<!--* freshness: {owner: 'eshr' reviewed: '2026-04-28'} *-->

# Testing in WebRTC

This document collects advice and best practices for writing tests in WebRTC,
covering GN macros, GoogleTest/GMock usage, and available utilities.

## Configure GN Macros

### Use `rtc_cc_test` for new unit tests

As part of the "Small Tests" infrastructure, use `rtc_cc_test` for new unit
tests. It defines a library and a standalone binary (prefixed with the folder
name and suffixed with `_bin`). To generate the binary, run autoninja with a
"\_bin" suffix to the target - `autoninja -C out/Default pc:proxy_unittest_bin`
will generate "out/Default/pc_proxy_unittest_bin" as your binary.

It should normally have a single source file.

Use `rtc_test_suite` to aggregate `rtc_cc_test` targets into larger
"mega-targets" for CI/CQ (e.g., `peerconnection_unittests`). Each `rtc_cc_test`
targets must be in exactly one `rtc_test_suite` target.

Refer to \[add-new-test-binary.md\](add-new-test-binary.md) for details on how
to add the binary for a new test suite to the infrastructure.

### Legacy: Using `rtc_test` to define test binaries

The `rtc_test` template is the traditional way to define test binaries in
WebRTC. It automatically adds `//test:test_main` as a dependency, providing the
standard `main()` function for running GoogleTest.

- **Example**:

  ```gn
  import("//webrtc.gni")

  rtc_test("my_unittest") {
    sources = [ "my_unittest.cc" ]
    deps = [
      ":my_library",
      "//test:test_support",
    ]
  }
  ```

  New test suites should be defined using rtc_test_suite and rtc_cc_test.

### Prefer `rtc_library` for test support

`rtc_library` is preferred for most targets (including test support code). It
automatically switches between `source_set` and `static_library` based on
configuration and the `testonly` flag.

## Follow GoogleTest and GMock Best Practices

These are documented in the
[Google testing blog](https://testing.googleblog.com/).

Refer to the
[GMock Matchers Reference](https://google.github.io/googletest/reference/matchers.html)
for a full list of available matchers.

### In WebRTC, include wrappers instead of raw headers

Always include `test/gtest.h` and `test/gmock.h` instead of the raw
GoogleTest/GMock headers. These wrappers handle warning suppressions and exports
correctly for WebRTC.

### Use `EXPECT_TRUE` and `EXPECT_FALSE` only for booleans

Use these macros for pure boolean comparisons only. Do not rely on implicit
conversions (e.g., checking if a pointer is non-null).

```cpp {.bad}
EXPECT_TRUE(pointer); // BAD: implicit conversion to bool
EXPECT_TRUE(integer_value); // BAD: implicit conversion
```

```cpp {.good}
using ::testing::NotNull;

EXPECT_NE(pointer, nullptr);
EXPECT_THAT(pointer, NotNull());
EXPECT_NE(integer_value, 0);
```

See [the relevant Abseil tips](https://abseil.io/tips/141) for details.

Note that `using` at the beginning of the file is
[recommended in gmock](https://google.github.io/googletest/gmock_cook_book.html).

### Prefer `EXPECT_THAT` for complex evaluations

`EXPECT_EQ`, `EXPECT_LE`, `EXPECT_LT`, `EXPECT_GE`, `EXPECT_GT` are acceptable
for simple cases. Prefer `EXPECT_THAT` and matchers for anything with complex
evaluations or when better error messages are needed.

```cpp {.bad}
EXPECT_TRUE(vec.size() == 1 && vec[0] == "val"); // poor failure message
```

```cpp {.good}
using ::testing::ElementsAre;

EXPECT_THAT(vec, ElementsAre("val"));
EXPECT_LE(value, 10); // okay for simple cases
```

### Avoid Yoda matching

Always put the **tested value first** and the **constant/expected value last**
in all expectations.

```cpp {.bad}
EXPECT_EQ(0, value);
```

```cpp {.good}
EXPECT_EQ(value, 0);
```

### Use `ASSERT_` for fatal conditions

Prefer `EXPECT_` for the normal case. This allows you to report several errors
from one single test run.

Use `ASSERT_` if failing the condition would cause a crash or undefined behavior
in subsequent code, or if failing the check would make later tests irrelevant
(e.g., checking if a pointer is null before dereferencing it).

This is also recommended by the
[GoogleTest primer](https://google.github.io/googletest/primer.html#assertions).

### Avoid expectations in helper functions

Helper functions in tests that contain expectations (`EXPECT_`/`ASSERT_`) are
discouraged. Instead, use matchers to make tests more readable and provide
better failure messages. You can create custom matchers in three ways:

1. **Returning a Matcher Combination**: Combine existing matchers.
   ```cpp
   auto FirstElementIs(int x) {
     return ::testing::AllOf(
         ::testing::Not(::testing::IsEmpty()),
         ::testing::ResultOf([](const auto& v) { return v.front(); }, ::testing::Eq(x)));
   }
   ```
2. **Using `MATCHER_P` Macros**: For simple parameterized matchers.
   - Example in [test/fake_encoded_frame.h](../test/fake_encoded_frame.h):
     ```cpp
     MATCHER_P(WithId, id, "") {
       return arg.Id() == id;
     }
     ```
3. **Implementing a Matcher Class**: For complex matchers that need to provide
   detailed explanations.
   - Example in [test/near_matcher.h](../test/near_matcher.h) which implements a
     `NearMatcher` for time types.
   - **Usage Example**:
     ```cpp
     #include "test/near_matcher.h"
     // ...
     EXPECT_THAT(actual_timestamp, webrtc::Near(expected_timestamp, TimeDelta::Millis(5)));
     ```

More information about writing matchers is found in the
[GMock cookbook](https://google.github.io/googletest/gmock_cook_book.html#NewMatchers).

## Use WebRTC Testing Utilities

### Use `GlobalSimulatedTimeController` for simulated time

Use `GlobalSimulatedTimeController` to run tests that depend on time (e.g.,
pacing, timeouts) without waiting for real time to pass. It provides a `Clock`
and `TaskQueueFactory`. Prefer modern simulated time infrastructure over legacy
`ScopedFakeClock`.

### Create an `Environment` using `CreateTestEnvironment`

The `Environment` is the modern way to propagate global utilities (like `Clock`,
`TaskQueueFactory`, `FieldTrials`) through the codebase. Tests that exercise any
component using an `Environment` **must always create** an `Environment` using
`webrtc::CreateTestEnvironment` (defined in
[test/create_test_environment.h](../test/create_test_environment.h)) and pass it
to the components being tested.

Using `CreateEnvironment` will cause the test to ignore the command line
`force-fieldtrials` flag, so this should not be used in tests unless there are
specific reasons for using it.

### Avoid polling, use `WaitUntil` when needed

`webrtc::WaitUntil` (located in [test/wait_until.h](../test/wait_until.h)) is a
modern utility for waiting for a condition to become true. It is best to avoid
polling where possible, but when needed, use `WaitUntil` instead of manual
polling or sleeping. It polls a predicate using the `TimeController`.

### Use `RunLoop` for single-threaded async simulation

`webrtc::test::RunLoop` (located in `test/run_loop.h`) is a helper class for
tests that need to process tasks posted to a task queue but still want to run
everything on a single thread. It is useful for simulating async operations
simply.

### Select a Scenario Framework

Some of the available frameworks:

- **`Scenario`** (`test/scenario`): Best for **network and media quality**
  evaluation (e.g., bandwidth estimation, congestion control).
- **`PeerScenario`** (`test/peer_scenario`): Best for **signaling and
  PeerConnection API** level tests that require multiple threads and a simulated
  network but want to stay lightweight. **`PCLF** (`api/test/pclf`) is a
  framework for full integration tests.
- \*\*`IntegrationTestHelpers` (`pc/test/integration_test_helpers`) is an older
  set of tools that is heavily used for PeerConnection-related unit testing.

Other frameworks for more specialized purposes also exist. <--! Question: Should
we recommend one over the others? -->

### Mocking

A lot of classes have existing mocks. Mocks for classes used in `api` live in
`api/test`; there are some in `test`, but in general, mocks for internal classes
should live close to the class they mock.

Mocks should be "pure mocks" using `gmock`. If the test double needs to have
code in it, it should be called a fake. See
[this testing blog](https://testing.googleblog.com/2013/07/testing-on-toilet-know-your-test-doubles.html)
for terminology.

General advice on mocking is in the
[GMock cookbook](https://google.github.io/googletest/gmock_cook_book.html).

### Leverage Other Utilities

- **`FrameGenerator`**: Located in `test/frame_generator.h`; it is useful for
  generating video frames for testing video pipelines.

## Run Tests

### Use `gtest-parallel` for faster local execution

For faster local execution, use
`third_party/gtest-parallel/gtest-parallel <binary>`.

Note that some tests are timing dependent and may be flaky when run under
`gtest-parallel`.
