pub struct Subject<T> { /* private fields */ }Expand description
A value under test, paired with the source text of the expression that produced it.
Subject owns its value (the check! macro hands it over by value) and
borrows nothing, so it carries no lifetime parameter.
Implementations§
Source§impl<T> Subject<T>
impl<T> Subject<T>
Sourcepub fn new(
actual: T,
expr: &'static str,
module_path: &'static str,
) -> Subject<T>
pub fn new( actual: T, expr: &'static str, module_path: &'static str, ) -> Subject<T>
Pairs actual with the source text it came from and the module_path!()
of the call site. Called by check!; rarely
constructed directly.
module_path is only consulted by matches_snapshot,
which uses it to name the snapshot file; every other method ignores it.
Sourcepub fn satisfies<M>(self, matcher: M) -> Result<(), TestError>where
M: Matcher<T>,
pub fn satisfies<M>(self, matcher: M) -> Result<(), TestError>where
M: Matcher<T>,
Asserts that the value satisfies matcher.
Returns Ok(()) on a match and a TestError otherwise. The result is
#[must_use] (it is a Result), so a forgotten ? is a compiler
warning rather than a silently-passing assertion.
Sourcepub fn resolves_to<M>(
self,
matcher: M,
) -> impl Future<Output = Result<(), TestError>>
pub fn resolves_to<M>( self, matcher: M, ) -> impl Future<Output = Result<(), TestError>>
Awaits the future and asserts that its output satisfies matcher.
This is the async counterpart of satisfies: reach
for it when the expression handed to check! is a
Future. The matcher runs against the future’s output, so
check!(fut).resolves_to(eq(4)) is exactly
check!(fut.await).satisfies(eq(4)) without the intermediate binding.
The method itself is not async: it is #[track_caller] and returns
a future. The call-site location is captured synchronously when
resolves_to is called (an async fn could not be #[track_caller]),
then carried into the failure once the returned future is awaited.
use test_better_core::TestResult;
use test_better_matchers::{check, eq};
pollster::block_on(async {
check!(async { 2 + 2 }).resolves_to(eq(4)).await?;
TestResult::Ok(())
})Sourcepub fn completes_within(
self,
limit: Duration,
) -> impl Future<Output = Result<(), TestError>>where
T: Future + RuntimeAvailable,
pub fn completes_within(
self,
limit: Duration,
) -> impl Future<Output = Result<(), TestError>>where
T: Future + RuntimeAvailable,
Awaits the future, but fails if it does not finish within limit.
Like resolves_to, this is for a future-typed
subject and returns a future rather than being async itself, so the
#[track_caller] location is the call site. Unlike resolves_to, it
does not look at the output: the assertion is purely about time.
The timeout needs a runtime to provide its sleep, selected by a cargo
feature on test-better: tokio, async-std, or smol. With none
enabled, the T: RuntimeAvailable bound is unsatisfied and the call is
a compile error naming those flags.
use std::time::Duration;
use test_better::prelude::*;
check!(some_future())
.completes_within(Duration::from_millis(50))
.await?;Sourcepub fn matches_snapshot(self, name: &str) -> Result<(), TestError>where
T: Display,
pub fn matches_snapshot(self, name: &str) -> Result<(), TestError>where
T: Display,
Asserts that the value matches the snapshot stored under name.
The snapshot lives at tests/snapshots/<module-path>__<name>.snap in the
package under test, with <module-path> taken from the call site’s
module_path!(). On a normal run the value is compared against that
file; a difference (or a missing file) is a Snapshot failure, and the
difference is rendered with the standard line-oriented diff. Rerun the
test with UPDATE_SNAPSHOTS=1 to create the file the first time, or to
accept an intentional change.
The value only has to be Display: that is what gets written to and
compared against the file.
use test_better_core::TestResult;
use test_better_matchers::check;
// Run once with `UPDATE_SNAPSHOTS=1` to record the snapshot; later runs
// compare against `tests/snapshots/<module>__homepage.snap`.
check!("<h1>Hello</h1>").matches_snapshot("homepage")?;Sourcepub fn matches_snapshot_with(
self,
name: &str,
redactions: &Redactions,
) -> Result<(), TestError>where
T: Display,
pub fn matches_snapshot_with(
self,
name: &str,
redactions: &Redactions,
) -> Result<(), TestError>where
T: Display,
Like matches_snapshot, but runs redactions
over the value first.
Use this when the rendered value carries content that is not stable run to run (a generated UUID, a timestamp): the redactions rewrite those spans to fixed placeholders, so the snapshot file stays meaningful. Because the redactions run on every comparison, the placeholder is what is stored and what later runs compare against.
use test_better_core::TestResult;
use test_better_matchers::check;
use test_better_snapshot::Redactions;
let rendered = format!("created {}", uuid_of_new_record());
check!(rendered)
.matches_snapshot_with("record", &Redactions::new().redact_uuids())?;Sourcepub fn matches_inline_snapshot(self, expected: &str) -> Result<(), TestError>where
T: Display,
pub fn matches_inline_snapshot(self, expected: &str) -> Result<(), TestError>where
T: Display,
Asserts that the value matches the inline snapshot literal expected.
Unlike matches_snapshot, the snapshot lives
in the test source: expected is the snapshot. The literal is
normalized before comparison (a leading newline and the common
indentation are cosmetic), so it can be indented to match the
surrounding code.
On a mismatch with UPDATE_SNAPSHOTS unset this fails like any
assertion. With UPDATE_SNAPSHOTS=1 it records a pending patch under
target/test-better-pending/ and passes; the test-better-accept
companion binary rewrites the literal in the source from those patches.
A proc macro could not do this rewrite (it runs before the test), so the
work is split: this method captures the call-site location with
#[track_caller], the accept binary edits the file.
use test_better_core::TestResult;
use test_better_matchers::check;
check!(2 + 2).matches_inline_snapshot("4")?;Sourcepub fn matches_inline_snapshot_with(
self,
expected: &str,
redactions: &Redactions,
) -> Result<(), TestError>where
T: Display,
pub fn matches_inline_snapshot_with(
self,
expected: &str,
redactions: &Redactions,
) -> Result<(), TestError>where
T: Display,
Like matches_inline_snapshot, but
runs redactions over the value first.
The inline-snapshot counterpart of
matches_snapshot_with: redaction
rewrites non-deterministic spans to fixed placeholders before the
comparison, so UPDATE_SNAPSHOTS=1 records the redacted value as the
literal and later runs stay green.
use test_better_core::TestResult;
use test_better_matchers::check;
use test_better_snapshot::Redactions;
let rendered = format!("at {}", now_rfc3339());
check!(rendered).matches_inline_snapshot_with(
"at [timestamp]",
&Redactions::new().redact_rfc3339_timestamps(),
)?;