368 lines
12 KiB
Markdown
368 lines
12 KiB
Markdown
# GoogleTest Rust
|
|
|
|
[![crates.io][crates-badge]][crates-url]
|
|
[![docs.rs][docs-badge]][docs-url]
|
|
[![Apache licensed][license-badge]][license-url]
|
|
[![Build Status][actions-badge]][actions-url]
|
|
[![OpenSSF Best Practices][openssf-badge]][openssf-url]
|
|
|
|
[crates-badge]: https://img.shields.io/crates/v/googletest.svg
|
|
[crates-url]: https://crates.io/crates/googletest
|
|
[docs-badge]: https://img.shields.io/badge/docs.rs-googletest-66c2a5
|
|
[docs-url]: https://docs.rs/googletest/*/googletest/
|
|
[license-badge]: https://img.shields.io/badge/license-Apache-blue.svg
|
|
[license-url]: https://github.com/google/googletest-rust/blob/main/LICENSE
|
|
[actions-badge]: https://github.com/google/googletest-rust/workflows/CI/badge.svg
|
|
[actions-url]: https://github.com/google/googletest-rust/actions?query=workflow%3ACI+branch%3Amain
|
|
[openssf-badge]: https://www.bestpractices.dev/projects/10037/badge
|
|
[openssf-url]: https://www.bestpractices.dev/projects/10037
|
|
|
|
This library brings the rich assertion types of Google's C++ testing library
|
|
[GoogleTest](https://github.com/google/googletest) to Rust. It provides:
|
|
|
|
* A framework for writing matchers which can be combined to make a wide range
|
|
of assertions on data,
|
|
* A rich set of matchers providing similar functionality to those included in
|
|
[GoogleTest](https://google.github.io/googletest/reference/matchers.html),
|
|
and
|
|
* A new set of assertion macros offering similar functionality to those of
|
|
[GoogleTest](https://google.github.io/googletest/primer.html#assertions).
|
|
|
|
**The minimum supported Rust version is 1.85**.
|
|
|
|
> :warning: The API is not fully stable and may still be changed until we
|
|
> publish version 1.0.
|
|
>
|
|
> Moreover, any items or modules starting with `__` (double underscores) must
|
|
> not be used directly. Those items or modules are only for internal uses and
|
|
> their API may change without a major version update.
|
|
|
|
## Learning resources
|
|
|
|
If you're just getting started with `googletest`, consider going through
|
|
the first chapter of
|
|
["Advanced testing for Rust applications"](https://github.com/mainmatter/rust-advanced-testing-workshop),
|
|
a self-guided Rust course: it provides a guided introduction to the library,
|
|
with exercises to help you get comfortable with `googletest` macros,
|
|
its matchers and its overall philosophy.
|
|
|
|
## Assertions and matchers
|
|
|
|
The core of GoogleTest is its *matchers*. Matchers indicate what aspect of an
|
|
actual value one is asserting: (in-)equality, containment, regular expression
|
|
matching, and so on.
|
|
|
|
To make an assertion using a matcher, GoogleTest offers three macros:
|
|
|
|
* [`assert_that!`] panics if the assertion fails, aborting the test.
|
|
* [`expect_that!`] logs an assertion failure, marking the test as having
|
|
failed, but allows the test to continue running (called a _non-fatal
|
|
assertion_). It requires the use of the [`gtest`] attribute macro
|
|
on the test itself.
|
|
* [`verify_that!`] has no side effects and evaluates to a [`Result<()>`] whose
|
|
`Err` variant describes the assertion failure, if there is one. In
|
|
combination with the
|
|
[`?` operator](https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator),
|
|
this can be used to abort the test on assertion failure without panicking. It
|
|
is also the building block for the other two macros above.
|
|
|
|
For example:
|
|
|
|
```rust
|
|
use googletest::prelude::*;
|
|
|
|
#[test]
|
|
fn fails_and_panics() {
|
|
let value = 2;
|
|
assert_that!(value, eq(4));
|
|
}
|
|
|
|
#[gtest]
|
|
fn two_logged_failures() {
|
|
let value = 2;
|
|
expect_that!(value, eq(4)); // Test now failed, but continues executing.
|
|
expect_that!(value, eq(5)); // Second failure is also logged.
|
|
}
|
|
|
|
#[test]
|
|
fn fails_immediately_without_panic() -> Result<()> {
|
|
let value = 2;
|
|
verify_that!(value, eq(4))?; // Test fails and aborts.
|
|
verify_that!(value, eq(2))?; // Never executes.
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn simple_assertion() -> Result<()> {
|
|
let value = 2;
|
|
verify_that!(value, eq(4)) // One can also just return the last assertion.
|
|
}
|
|
```
|
|
|
|
This library includes a rich set of matchers, covering:
|
|
|
|
* Equality, numeric inequality, and approximate equality;
|
|
* Strings and regular expressions;
|
|
* Containers and set-theoretic matching.
|
|
|
|
Matchers are composable:
|
|
|
|
```rust
|
|
use googletest::prelude::*;
|
|
|
|
#[gtest]
|
|
fn contains_at_least_one_item_at_least_3() {
|
|
let value = vec![1, 2, 3];
|
|
expect_that!(value, contains(ge(3)));
|
|
}
|
|
```
|
|
|
|
They can also be logically combined:
|
|
|
|
```rust
|
|
use googletest::prelude::*;
|
|
|
|
#[gtest]
|
|
fn strictly_between_9_and_11() {
|
|
let value = 10;
|
|
expect_that!(value, gt(9).and(not(ge(11))));
|
|
}
|
|
```
|
|
|
|
## Pattern-matching
|
|
|
|
One can use the macro [`matches_pattern!`] to create a composite matcher for a
|
|
struct or enum that matches fields with other matchers:
|
|
|
|
```rust
|
|
use googletest::prelude::*;
|
|
|
|
struct AStruct {
|
|
a_field: i32,
|
|
another_field: i32,
|
|
a_third_field: &'static str,
|
|
}
|
|
|
|
#[test]
|
|
fn struct_has_expected_values() {
|
|
let value = AStruct {
|
|
a_field: 10,
|
|
another_field: 100,
|
|
a_third_field: "A correct value",
|
|
};
|
|
expect_that!(value, matches_pattern!(AStruct {
|
|
a_field: eq(10),
|
|
another_field: gt(50),
|
|
a_third_field: contains_substring("correct"),
|
|
}));
|
|
}
|
|
```
|
|
|
|
## Writing matchers
|
|
|
|
One can extend the library by writing additional matchers. To do so, create a
|
|
struct holding the matcher's data and have it implement the trait [`Matcher`]:
|
|
|
|
```rust
|
|
struct MyEqMatcher<T> {
|
|
expected: T,
|
|
}
|
|
|
|
impl<T: PartialEq + Debug + Copy> Matcher<T> for MyEqMatcher<T> {
|
|
fn matches(&self, actual: T) -> MatcherResult {
|
|
(self.expected == actual).into()
|
|
}
|
|
|
|
fn describe(&self, matcher_result: MatcherResult) -> String {
|
|
match matcher_result {
|
|
MatcherResult::Match => {
|
|
format!("is equal to {:?} the way I define it", self.expected)
|
|
}
|
|
MatcherResult::NoMatch => {
|
|
format!("isn't equal to {:?} the way I define it", self.expected)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
It is recommended to expose a function which constructs the matcher:
|
|
|
|
```rust
|
|
pub fn eq_my_way<T: PartialEq + Debug>(expected: T) -> impl Matcher<T> {
|
|
MyEqMatcher { expected }
|
|
}
|
|
```
|
|
|
|
The new matcher can then be used in the assertion macros:
|
|
|
|
```rust
|
|
#[gtest]
|
|
fn should_be_equal_by_my_definition() {
|
|
expect_that!(10, eq_my_way(10));
|
|
}
|
|
```
|
|
|
|
## Non-fatal assertions
|
|
|
|
Using non-fatal assertions, a single test is able to log multiple assertion
|
|
failures. Any single assertion failure causes the test to be considered having
|
|
failed, but execution continues until the test completes or otherwise aborts.
|
|
|
|
This is analogous to the `EXPECT_*` family of macros in GoogleTest.
|
|
|
|
To make a non-fatal assertion, use the macro [`expect_that!`]. The test must
|
|
also be marked with [`gtest`] instead of the Rust-standard `#[test]`.
|
|
|
|
```rust
|
|
use googletest::prelude::*;
|
|
|
|
#[gtest]
|
|
fn three_non_fatal_assertions() {
|
|
let value = 2;
|
|
expect_that!(value, eq(2)); // Passes; test still considered passing.
|
|
expect_that!(value, eq(3)); // Fails; logs failure and marks the test failed.
|
|
expect_that!(value, eq(4)); // A second failure, also logged.
|
|
}
|
|
```
|
|
|
|
This can be used in the same tests as `verify_that!`, in which case the test
|
|
function must also return [`Result<()>`]:
|
|
|
|
```rust
|
|
use googletest::prelude::*;
|
|
|
|
#[gtest]
|
|
fn failing_non_fatal_assertion() -> Result<()> {
|
|
let value = 2;
|
|
expect_that!(value, eq(3)); // Just marks the test as having failed.
|
|
verify_that!(value, eq(2))?; // Passes, so does not abort the test.
|
|
Ok(()) // Because of the failing expect_that! call above, the
|
|
// test fails despite returning Ok(())
|
|
}
|
|
```
|
|
|
|
```rust
|
|
use googletest::prelude::*;
|
|
|
|
#[gtest]
|
|
fn failing_fatal_assertion_after_non_fatal_assertion() -> Result<()> {
|
|
let value = 2;
|
|
verify_that!(value, eq(3))?; // Fails and aborts the test.
|
|
expect_that!(value, eq(3)); // Never executes, since the test already aborted.
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
### Interoperability
|
|
|
|
You can use the `#[gtest]` macro together with many other libraries
|
|
such as [rstest](https://crates.io/crates/rstest). Just apply both attribute
|
|
macros to the test:
|
|
|
|
```rust
|
|
#[gtest]
|
|
#[rstest]
|
|
#[case(1)]
|
|
#[case(2)]
|
|
#[case(3)]
|
|
fn rstest_works_with_google_test(#[case] value: u32) -> Result<()> {
|
|
verify_that!(value, gt(0))
|
|
}
|
|
```
|
|
|
|
Make sure to put `#[gtest]` *before* `#[rstest]`. Otherwise the
|
|
annotated test will run twice, since both macros will attempt to register a test
|
|
with the Rust test harness.
|
|
|
|
The macro also works together with
|
|
[async tests with Tokio](https://docs.rs/tokio/latest/tokio/attr.gtest.html) in
|
|
the same way:
|
|
|
|
```rust
|
|
#[gtest]
|
|
#[tokio::test]
|
|
async fn should_work_with_tokio() -> Result<()> {
|
|
verify_that!(3, gt(0))
|
|
}
|
|
```
|
|
|
|
There is one caveat when running async tests: test failure reporting through
|
|
`and_log_failure` will not work properly if the assertion occurs on a different
|
|
thread than runs the test.
|
|
|
|
## Predicate assertions
|
|
|
|
The macro [`verify_pred!`] provides predicate assertions analogous to
|
|
GoogleTest's `EXPECT_PRED` family of macros. Wrap an invocation of a predicate
|
|
in a `verify_pred!` invocation to turn that into a test assertion which passes
|
|
precisely when the predicate returns `true`:
|
|
|
|
```rust
|
|
fn stuff_is_correct(x: i32, y: i32) -> bool {
|
|
x == y
|
|
}
|
|
|
|
let x = 3;
|
|
let y = 4;
|
|
verify_pred!(stuff_is_correct(x, y))?;
|
|
```
|
|
|
|
The assertion failure message shows the arguments and the values to which they
|
|
evaluate:
|
|
|
|
```
|
|
stuff_is_correct(x, y) was false with
|
|
x = 3,
|
|
y = 4
|
|
```
|
|
|
|
The `verify_pred!` invocation evaluates to a [`Result<()>`] just like
|
|
[`verify_that!`]. There is also a macro [`expect_pred!`] to make a non-fatal
|
|
predicaticate assertion.
|
|
|
|
## Unconditionally generating a test failure
|
|
|
|
The macro [`fail!`] unconditionally evaluates to a `Result` indicating a test
|
|
failure. It can be used analogously to [`verify_that!`] and [`verify_pred!`] to
|
|
cause a test to fail, with an optional formatted message:
|
|
|
|
```rust
|
|
#[test]
|
|
fn always_fails() -> Result<()> {
|
|
fail!("This test must fail with {}", "today")
|
|
}
|
|
```
|
|
|
|
## Configuration
|
|
|
|
This library is configurable through environment variables. Since the
|
|
configuration does not impact whether a test fails or not but how a failure is
|
|
displayed, we recommend setting those variables in the personal
|
|
`~/.cargo/config.toml` instead of in the project-scoped `Cargo.toml`.
|
|
|
|
### Configuration variable list
|
|
|
|
| Variable name | Description |
|
|
| ------------- | ------------------------------------------------------- |
|
|
| NO_COLOR | Disables colored output. See <https://no-color.org/>. |
|
|
| FORCE_COLOR | Forces colors even when the output is piped to a file. |
|
|
|
|
## Contributing Changes
|
|
|
|
Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute
|
|
to this project.
|
|
|
|
[`and_log_failure()`]: https://docs.rs/googletest/*/googletest/trait.GoogleTestSupport.html#tymethod.and_log_failure
|
|
[`assert_that!`]: https://docs.rs/googletest/*/googletest/macro.assert_that.html
|
|
[`expect_pred!`]: https://docs.rs/googletest/*/googletest/macro.expect_pred.html
|
|
[`expect_that!`]: https://docs.rs/googletest/*/googletest/macro.expect_that.html
|
|
[`fail!`]: https://docs.rs/googletest/*/googletest/macro.fail.html
|
|
[`gtest`]: https://docs.rs/googletest/*/googletest/attr.gtest.html
|
|
[`matches_pattern!`]: https://docs.rs/googletest/*/googletest/macro.matches_pattern.html
|
|
[`verify_pred!`]: https://docs.rs/googletest/*/googletest/macro.verify_pred.html
|
|
[`verify_that!`]: https://docs.rs/googletest/*/googletest/macro.verify_that.html
|
|
[`Describe`]: https://docs.rs/googletest/*/googletest/matcher/trait.Describe.html
|
|
[`Matcher`]: https://docs.rs/googletest/*/googletest/matcher/trait.Matcher.html
|
|
[`Result<()>`]: https://docs.rs/googletest/*/googletest/type.Result.html
|