3 releases (breaking)
0.3.0 | Nov 17, 2023 |
---|---|
0.2.0 | Jun 15, 2023 |
0.1.0 | Apr 4, 2023 |
#258 in Testing
Used in ndjson-stream
500KB
10K
SLoC
Kernal
Kernal (Kernal Extensive Rust Natural Assertion Language) allows you to use fluent assertions in
Rust tests. That is, instead of writing assert_eq!(my_vec.len(), 10)
, you can write
assert_that!(my_vec).has_length(10)
, making your tests more readable and enabling the framework to
provide more expressive error messages. Kernal aims to provide specialized assertions for as many
commonly tested properties as possible.
Writing an assertion
To write an assertion over a value, start with assert_that!(<your value>)
, which gives you an
instance on which you can call associated functions to make your assertions. Import the specialized
extension traits, such as StringAssertions
for special assertions for String
s, from the
prelude
module. This gives you all imports you need to write every assertion supported by Kernal.
use kernal::prelude::*;
assert_that!("hello world").contains("world");
Chaining
Every assertion returns the same asserter instance to continue writing assertions on the same value. In addition, some extension traits define mapping methods that manipulate the data in some way and return asserter instances on the new data.
assert_that!("almost")
.has_char_length(6)
.ends_with("most")
.to_chars()
.is_sorted_in_strictly_ascending_order();
Creating custom assertions
Kernal allows the creation of custom assertions to test instances of your types in a more natural
way. This is achieved by grouping assertions you want to offer for specific types into traits, which
are then implemented on the output type of the assert_that
macro. For more details, view the
crate-level documentation. The example below demonstrates this process.
// Our type for which we want to write assertions.
struct Vector2f32 { x: f32, y: f32 }
// The custom assertion trait we will later implement on `AssertThat`.
trait Vector2f32Assertions {
// The custom assertion we want to supply. It is recommended to take an owned `self` and
// return the same instance to support chaining.
fn has_euclidean_norm(self, expected_norm: f32, epsilon: f32) -> AssertThat<Vector2f32>;
}
impl Vector2f32Assertions for AssertThat<Vector2f32> {
fn has_euclidean_norm(self, expected_norm: f32, epsilon: f32) -> AssertThat<Vector2f32> {
// We get our data with `self.data()`, supplied by `AssertThatData`
let vector = self.data();
let actual_norm = (vector.x * vector.x + vector.y * vector.y).sqrt();
if (actual_norm - expected_norm).abs() > epsilon {
// Here we must fail - using the `Failure` struct
Failure::new(&self)
.expected_it(format!("to have a euclidean norm within <{}> of <{}>",
epsilon, expected_norm))
.but_it(format!("was <({}, {})>, with a euclidean norm of <{}>",
vector.x, vector.y, actual_norm))
.fail()
}
// Here the test passes, so we return `self` for chaining
self
}
}