Hypothesis-like property testing for Rust

Related tags

Testing proptest
Overview

Proptest

Build Status Build status

Introduction

Proptest is a property testing framework (i.e., the QuickCheck family) inspired by the Hypothesis framework for Python. It allows to test that certain properties of your code hold for arbitrary inputs, and if a failure is found, automatically finds the minimal test case to reproduce the problem. Unlike QuickCheck, generation and shrinking is defined on a per-value basis instead of per-type, which makes it more flexible and simplifies composition.

Status of this crate

The crate is fairly close to being feature-complete and has not seen substantial architectural changes in quite some time. At this point, it mainly sees passive maintenance.

See the changelog for a full list of substantial historical changes, breaking and otherwise.

What is property testing?

Property testing is a system of testing code by checking that certain properties of its output or behaviour are fulfilled for all inputs. These inputs are generated automatically, and, critically, when a failing input is found, the input is automatically reduced to a minimal test case.

Property testing is best used to complement traditional unit testing (i.e., using specific inputs chosen by hand). Traditional tests can test specific known edge cases, simple inputs, and inputs that were known in the past to reveal bugs, whereas property tests will search for more complicated inputs that cause problems.

Getting Started

Let's say we want to make a function that parses dates of the form YYYY-MM-DD. We're not going to worry about validating the date, any triple of integers is fine. So let's bang something out real quick.

fn parse_date(s: &str) -> Option<(u32, u32, u32)> {
    if 10 != s.len() { return None; }
    if "-" != &s[4..5] || "-" != &s[7..8] { return None; }

    let year = &s[0..4];
    let month = &s[6..7];
    let day = &s[8..10];

    year.parse::<u32>().ok().and_then(
        |y| month.parse::<u32>().ok().and_then(
            |m| day.parse::<u32>().ok().map(
                |d| (y, m, d))))
}

It compiles, that means it works, right? Maybe not, let's add some tests.

#[test]
fn test_parse_date() {
    assert_eq!(None, parse_date("2017-06-1"));
    assert_eq!(None, parse_date("2017-06-170"));
    assert_eq!(None, parse_date("2017006-17"));
    assert_eq!(None, parse_date("2017-06017"));
    assert_eq!(Some((2017, 06, 17)), parse_date("2017-06-17"));
}

Tests pass, deploy to production! But now your application starts crashing, and people are upset that you moved Christmas to February. Maybe we need to be a bit more thorough.

In Cargo.toml, add

[dev-dependencies]
proptest = "1.0.0"

Now we can add some property tests to our date parser. But how do we test the date parser for arbitrary inputs, without making another date parser in the test to validate it? We won't need to as long as we choose our inputs and properties correctly. But before correctness, there's actually an even simpler property to test: The function should not crash. Let's start there.

// Bring the macros and other important things into scope.
use proptest::prelude::*;

proptest! {
    #[test]
    fn doesnt_crash(s in "\\PC*") {
        parse_date(&s);
    }
}

What this does is take a literally random &String (ignore \\PC* for the moment, we'll get back to that — if you've already figured it out, contain your excitement for a bit) and give it to parse_date() and then throw the output away.

When we run this, we get a bunch of scary-looking output, eventually ending with

thread 'main' panicked at 'Test failed: byte index 4 is not a char boundary; it is inside 'ௗ' (bytes 2..5) of `aAௗ0㌀0`; minimal failing input: s = "aAௗ0㌀0"
	successes: 102
	local rejects: 0
	global rejects: 0
'

If we look at the top directory after the test fails, we'll see a new proptest-regressions directory, which contains some files corresponding to source files containing failing test cases. These are failure persistence files. The first thing we should do is add these to source control.

$ git add proptest-regressions

The next thing we should do is copy the failing case to a traditional unit test since it has exposed a bug not similar to what we've tested in the past.

#[test]
fn test_unicode_gibberish() {
    assert_eq!(None, parse_date("aAௗ0㌀0"));
}

Now, let's see what happened... we forgot about UTF-8! You can't just blindly slice strings since you could split a character, in this case that Tamil diacritic placed atop other characters in the string.

In the interest of making the code changes as small as possible, we'll just check that the string is ASCII and reject anything that isn't.

fn parse_date(s: &str) -> Option<(u32, u32, u32)> {
    if 10 != s.len() { return None; }

    // NEW: Ignore non-ASCII strings so we don't need to deal with Unicode.
    if !s.is_ascii() { return None; }

    if "-" != &s[4..5] || "-" != &s[7..8] { return None; }

    let year = &s[0..4];
    let month = &s[6..7];
    let day = &s[8..10];

    year.parse::<u32>().ok().and_then(
        |y| month.parse::<u32>().ok().and_then(
            |m| day.parse::<u32>().ok().map(
                |d| (y, m, d))))
}

The tests pass now! But we know there are still more problems, so let's test more properties.

Another property we want from our code is that it parses every valid date. We can add another test to the proptest! section:

proptest! {
    // snip...

    #[test]
    fn parses_all_valid_dates(s in "[0-9]{4}-[0-9]{2}-[0-9]{2}") {
        parse_date(&s).unwrap();
    }
}

The thing to the right-hand side of in is actually a regular expression, and s is chosen from strings which match it. So in our previous test, "\\PC*" was generating arbitrary strings composed of arbitrary non-control characters. Now, we generate things in the YYYY-MM-DD format.

The new test passes, so let's move on to something else.

The final property we want to check is that the dates are actually parsed correctly. Now, we can't do this by generating strings — we'd end up just reimplementing the date parser in the test! Instead, we start from the expected output, generate the string, and check that it gets parsed back.

proptest! {
    // snip...

    #[test]
    fn parses_date_back_to_original(y in 0u32..10000,
                                    m in 1u32..13, d in 1u32..32) {
        let (y2, m2, d2) = parse_date(
            &format!("{:04}-{:02}-{:02}", y, m, d)).unwrap();
        // prop_assert_eq! is basically the same as assert_eq!, but doesn't
        // cause a bunch of panic messages to be printed on intermediate
        // test failures. Which one to use is largely a matter of taste.
        prop_assert_eq!((y, m, d), (y2, m2, d2));
    }
}

Here, we see that besides regexes, we can use any expression which is a proptest::strategy::Strategy, in this case, integer ranges.

The test fails when we run it. Though there's not much output this time.

thread 'main' panicked at 'Test failed: assertion failed: `(left == right)` (left: `(0, 10, 1)`, right: `(0, 0, 1)`) at examples/dateparser_v2.rs:46; minimal failing input: y = 0, m = 10, d = 1
	successes: 2
	local rejects: 0
	global rejects: 0
', examples/dateparser_v2.rs:33
note: Run with `RUST_BACKTRACE=1` for a backtrace.

The failing input is (y, m, d) = (0, 10, 1), which is a rather specific output. Before thinking about why this breaks the code, let's look at what proptest did to arrive at this value. At the start of our test function, insert

    println!("y = {}, m = {}, d = {}", y, m, d);

Running the test again, we get something like this:

y = 2497, m = 8, d = 27
y = 9641, m = 8, d = 18
y = 7360, m = 12, d = 20
y = 3680, m = 12, d = 20
y = 1840, m = 12, d = 20
y = 920, m = 12, d = 20
y = 460, m = 12, d = 20
y = 230, m = 12, d = 20
y = 115, m = 12, d = 20
y = 57, m = 12, d = 20
y = 28, m = 12, d = 20
y = 14, m = 12, d = 20
y = 7, m = 12, d = 20
y = 3, m = 12, d = 20
y = 1, m = 12, d = 20
y = 0, m = 12, d = 20
y = 0, m = 6, d = 20
y = 0, m = 9, d = 20
y = 0, m = 11, d = 20
y = 0, m = 10, d = 20
y = 0, m = 10, d = 10
y = 0, m = 10, d = 5
y = 0, m = 10, d = 3
y = 0, m = 10, d = 2
y = 0, m = 10, d = 1

The test failure message said there were two successful cases; we see these at the very top, 2497-08-27 and 9641-08-18. The next case, 7360-12-20, failed. There's nothing immediately obviously special about this date. Fortunately, proptest reduced it to a much simpler case. First, it rapidly reduced the y input to 0 at the beginning, and similarly reduced the d input to the minimum allowable value of 1 at the end. Between those two, though, we see something different: it tried to shrink 12 to 6, but then ended up raising it back up to 10. This is because the 0000-06-20 and 0000-09-20 test cases passed.

In the end, we get the date 0000-10-01, which apparently gets parsed as 0000-00-01. Again, this failing case was added to the failure persistence file, and we should add this as its own unit test:

$ git add proptest-regressions
#[test]
fn test_october_first() {
    assert_eq!(Some((0, 10, 1)), parse_date("0000-10-01"));
}

Now to figure out what's broken in the code. Even without the intermediate input, we can say with reasonable confidence that the year and day parts don't come into the picture since both were reduced to the minimum allowable input. The month input was not, but was reduced to 10. This means we can infer that there's something special about 10 that doesn't hold for 9. In this case, that "special something" is being two digits wide. In our code:

    let month = &s[6..7];

We were off by one, and need to use the range 5..7. After fixing this, the test passes.

The proptest! macro has some additional syntax, including for setting configuration for things like the number of test cases to generate. See its documentation for more details.

Differences between QuickCheck and Proptest

QuickCheck and Proptest are similar in many ways: both generate random inputs for a function to check certain properties, and automatically shrink inputs to minimal failing cases.

The one big difference is that QuickCheck generates and shrinks values based on type alone, whereas Proptest uses explicit Strategy objects. The QuickCheck approach has a lot of disadvantages in comparison:

  • QuickCheck can only define one generator and shrinker per type. If you need a custom generation strategy, you need to wrap it in a newtype and implement traits on that by hand. In Proptest, you can define arbitrarily many different strategies for the same type, and there are plenty built-in.

  • For the same reason, QuickCheck has a single "size" configuration that tries to define the range of values generated. If you need an integer between 0 and 100 and another between 0 and 1000, you probably need to do another newtype. In Proptest, you can directly just express that you want a 0..100 integer and a 0..1000 integer.

  • Types in QuickCheck are not easily composable. Defining Arbitrary and Shrink for a new struct which is simply produced by the composition of its fields requires implementing both by hand, including a bidirectional mapping between the struct and a tuple of its fields. In Proptest, you can make a tuple of the desired components and then prop_map it into the desired form. Shrinking happens automatically in terms of the input types.

  • Because constraints on values cannot be expressed in QuickCheck, generation and shrinking may lead to a lot of input rejections. Strategies in Proptest are aware of simple constraints and do not generate or shrink to values that violate them.

The author of Hypothesis also has an article on this topic.

Of course, there's also some relative downsides that fall out of what Proptest does differently:

  • Generating complex values in Proptest can be up to an order of magnitude slower than in QuickCheck. This is because QuickCheck performs stateless shrinking based on the output value, whereas Proptest must hold on to all the intermediate states and relationships in order for its richer shrinking model to work.

Limitations of Property Testing

Given infinite time, property testing will eventually explore the whole input space to a test. However, time is not infinite, so only a randomly sampled portion of the input space can be explored. This means that property testing is extremely unlikely to find single-value edge cases in a large space. For example, the following test will virtually always pass:

use proptest::prelude::*;

proptest! {
    #[test]
    fn i64_abs_is_never_negative(a: i64) {
        // This actually fails if a == i64::MIN, but randomly picking one
        // specific value out of 2⁶⁴ is overwhelmingly unlikely.
        assert!(a.abs() >= 0);
    }
}

Because of this, traditional unit testing with intelligently selected cases is still necessary for many kinds of problems.

Similarly, in some cases it can be hard or impossible to define a strategy which actually produces useful inputs. A strategy of .{1,4096} may be great to fuzz a C parser, but is highly unlikely to produce anything that makes it to a code generator.

Acknowledgements

This crate wouldn't have come into existence had it not been for the Rust port of QuickCheck and the regex_generate crate which gave wonderful examples of what is possible.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Comments
  • `sample()` and `select()` functions are missing

    `sample()` and `select()` functions are missing

    My use case is a graph, where all nodes are randomly created, and then I want to select a subset for each node to connect to when I create the actual graph.

    However, there doesn't seem to be either a sample() or select() api with which to do this.

    opened by vitiral 52
  • Is Proptest abandoned?

    Is Proptest abandoned?

    There are a lot of open PRs, the project's own tests no longer pass (since #258) (TBH I can't even get the tests to compile)

    Not to be one of those entitled downstream users, but can @AltSysrq please let us know the state of the project, or if someone should fork/takeover as the canonical crate?

    Many thanks in advance

    opened by russelldb 34
  • Tracking issue for `proptest_derive`

    Tracking issue for `proptest_derive`

    This issue tracks things we need to do before shipping proptest_derive 0.1:

    • [x] Setup workspace
    • [x] Test proptest_derive with (Travis) CI
    • [x] Invite @AltSysrq as crate owner on crates.io
    • [x] Implement #[proptest(regex = "...")]
      • PR in https://github.com/AltSysrq/proptest/pull/103.
    • [x] Review the base function of the macro... is there anything we want to change?
      • [x] Should the base attribute be proptest or prop? or something else?
      • [x] Are the "sub-attributes" appropriately named and do they function well?
        • [x] weight (shorthand: w)
        • [x] strategy
        • [x] value
        • [x] params
        • [x] no_params
        • [x] skip
        • [x] no_bound
        • [x] filter
    • [x] Write user facing documentation in the form of an mdBook akin to https://serde.rs/ or https://mcarton.github.io/rust-derivative/ (example: https://rust-lang-nursery.github.io/edition-guide/introduction.html).
      • [x] Flesh out basic structure; should we include all of proptest or just proptest_derive for now?
      • [x] Write the guide
    • [x] Issues
      • [x] #[proptest(value = "4a")] is accepted by the macro but of course is ultimately invalid syntax.
    opened by Centril 17
  • The proptest_derive crate & #[derive(Arbitrary)]

    The proptest_derive crate & #[derive(Arbitrary)]

    This PR adds the crate proptest_derive to this repo.

    The advantage of not having this in a separate repo is that I expect both crates will be easier to maintain and test if they are in a single place. Another crate that does this is serde which sports its serde_derive crate here.

    The PR is pretty massive in size (sorry about that) but it is 100% consisting of additions and no code is touched outside of the proptest-derive directory. I recommend checking out my branch and starting from the tests directory to see what is supported and what is explicitly rejected.

    I'm sure there are places where the code can be refactored and improved, but I'd like to avoid making too many changes to this PR. We can of course make design changes and code improvements later.

    Some things TODO after merging this PR (to a separate branch, not master):

    1. Setup a workspace. Ideally, all the code for the proptest crate should go in its own directory in the root and proptest-derive should also be in the root.

    2. Make sure proptest-derive is tested with Travis CI and AppVeyor CI. For now, I have not made any changes to .travis.yml but there are plenty of tests (+50% of the code). These should all be run with a nightly compiler (because compiletest_rs wants it for pretty tests and because attr_literals is unstable). Until we've ensured that tests are run, it would be inadvisable to make breaking changes to proptest itself.

    3. I have to give you perms on crates.io so you can publish updates to proptest-derive at the same time as proptest.

    4. Release a 0.1 of proptest-derive.

    Here are some TODOs into the future:

    1. We should figure out what to do with self-recursive and mutually-recursive types. These are not supported at all and will blow the stack if attempted.

    2. Write extensive documentation (ideally in the form of an mdbook (see #36)). I haven't had the time to do that yet but I'll start on it ASAP.

    3. Improve error messages with correct spans and such things.

    4. Eventually use the custom error message API in https://internals.rust-lang.org/t/custom-error-diagnostics-with-procedural-macros-on-almost-stable-rust/8113 to segregate errors by warnings and so on...

    opened by Centril 17
  • Help implementing Arbitrary on an array of ArrayVec

    Help implementing Arbitrary on an array of ArrayVec

    This is a helpful library, and in many cases, I've found it to be more ergonomic than the quickcheck library.

    One issue I'm struggling with, though, is implementing Arbitrary for an array of ArrayVec values. I think the ideal code would look like:

    struct MyArrayVec(ArrayVec<[u8; 16]>); // Newtype-style wrapper
    
    impl Arbitrary for MyArrayVec {
        // what goes here?
    }
    
    #[derive(Arbitrary)]
    struct MyStruct {
      items: [MyArrayVec; 10],
    }
    

    But, I don't know the idiomatic way to do it. I see that the arbitrary! macro is not public in this crate (not that I would know how to use it). Perhaps the answer to this question could be added to a FAQ or HOWTO document. Thanks!

    opened by rw 15
  • does this replace quickcheck completely?

    does this replace quickcheck completely?

    If the answer is yes, then I'd be happy to start directing users your way. In particular, I read your section on the differences between QuickCheck and Proptest and all of them seem like advantages in favor of proptest over quickcheck. Is this an exhaustive comparison? That is, does quickcheck have any advantages over proptest?

    Apologies for the drive by comment. I haven't actually tried to use proptest yet, but figured I'd just get the ball rolling here. :)

    opened by BurntSushi 13
  • Make union value trees lazily generated.

    Make union value trees lazily generated.

    I wanted to put this up to get some early opinions. Note that there's the one API change that happens: the type param for UnionValueTree is no longer the tree -- it's the strategy. I don't think this should affect any actual code, but wanted to flag this just in case.

    I'll do lazy tuples as well if this looks good.

    Closes #143.

    opened by sunshowers 12
  • Strategy::prop_and_then for composing strategies

    Strategy::prop_and_then for composing strategies

    It would be nice to have the equivalent of {Option, Future}::and_then for composing Strategies. Composition can already be done via prop_compose! (which is probably more flexible), but for simply gluing together two strategies in a straight line and_then can be more straightforward and readable. Here's a sketch of what the API might look like:

        /// Returns a strategy which chains another strategy produced by `f` to this one.
        ///
        /// TODO: describe shrinking behavior
        fn prop_and_then<T, U, F>(self, f: F) -> AndThen<Self, U>
        where
            U: Strategy<Value=T>,
            F: FnOnce(Self::Value) -> U
        {
            ...
        }
    
    
    question 
    opened by danburkert 11
  • Strategy does not implement Sync

    Strategy does not implement Sync

    I'm not sure if there is a technical reason this is not possible, but I thought I would check.

    I would like to create the regex strategy using lazy_static! but Strategies don't implement Sync.

    Thanks!

    error[E0277]: the trait bound `proptest::strategy::Strategy<Value=std::boxed::Box<proptest::strategy::ValueTree<Value=std::string::String> + 'static>> + 'static: std::marker::Sync` is not satisfied
      --> src/test_name.rs:38:1
       |
    38 | / lazy_static!{
    39 | |     static ref GEN_NAME_PROP: prop::string::RegexGeneratorStrategy<String> =
    40 | |         prop::string::string_regex(GEN_NAME_RE).unwrap();
    41 | | }
       | |_^ `proptest::strategy::Strategy<Value=std::boxed::Box<proptest::strategy::ValueTree<Value=std::string::String> + 'static>> + 'static` cannot be shared between threads safely
       |
       = help: the trait `std::marker::Sync` is not implemented for `proptest::strategy::Strategy<Value=std::boxed::Box<proptest::strategy::ValueTree<Value=std::string::String> + 'static>> + 'static`
       = note: required because of the requirements on the impl of `std::marker::Sync` for `std::ptr::Unique<proptest::strategy::Strategy<Value=std::boxed::Box<proptest::strategy::ValueTree<Value=std::string::String
    > + 'static>> + 'static>`
       = note: required because it appears within the type `std::boxed::Box<proptest::strategy::Strategy<Value=std::boxed::Box<proptest::strategy::ValueTree<Value=std::string::String> + 'static>> + 'static>`
       = note: required because it appears within the type `proptest::string::RegexGeneratorStrategy<std::string::String>`
       = note: required by `lazy_static::lazy::Lazy`
       = note: this error originates in a macro outside of the current crate
    
    error: aborting due to previous error
    
    error: Could not compile `artifact-data`.
    
    opened by vitiral 11
  • Update to rand 0.7

    Update to rand 0.7

    The primary change is due to rand's new error handling. With rand 0.7, the rand::Error type now contains either a boxed Error (when std is available) or a NonZeroU32 (in no_std cases). As a result, I've introduced a new PassThroughExhaustedError type. When std is available, the implementation creates a rand::Error by boxing a PassThroughExhaustedError, while in no_std cases, it uses an error code representing the error.

    Fixes #168.

    opened by jturner314 10
  • 128-bit support

    128-bit support

    error[E0277]: the trait bound `std::ops::Range<u128>: proptest::strategy::Strategy` is not satisfied
      --> tests\jump_tests.rs:74:1
       |
    74 | / proptest! {
    75 | |   #[test]
    76 | |   fn prop_for_jump_lcg128(s in 0..core::u128::MAX, j in 0..core::u16::MAX) {
    77 | |     // Note(Lokathor): Yes, `j` is supposed to be only up to `u16`, or the test
    ...  |
    89 | |   }
    90 | | }
       | |_^ the trait `proptest::strategy::Strategy` is not implemented for `std::ops::Range<u128>
    
    opened by Lokathor 10
  • Multi-core testing

    Multi-core testing

    I found that proptest only utilizes one core. The task of running a function for a number of inputs seems embarassingly parallel. Is there a way to run proptest with multiple threads?

    opened by GoldsteinE 0
  • [fix-ci-nigtly]

    [fix-ci-nigtly]

    ci was broken on nightly this series of fixes should correct it

    • dependencies.x86 was bumped to latest current version. x86 crate does not advertise an MSRV, but this was just broken on even our MSRV because the old x86 version was using a macro removed from rust, so bumping to latest seems fair.
    • the calculation for the arbitrary impl of Layout was using a max_size that was too large and overflowing Layout. this has been fixed.
    • test for arbitrary AllocError was referering to AllocErr which does not exist, this was fixed.
    • NoneError has been removed from rust so it was subsequently removed from proptest. It was blocking compilation. evidence: https://github.com/rust-lang/rust/issues/85614
    • try_reserve is stable so removed from unstable features
    • try_trait has been changed to try_trait_v2 so that was fixed in Cargo.toml.
    opened by rex-remind101 2
  • Provide a way to also supply multiple manual test cases, that is, parameterized or explicit cases.

    Provide a way to also supply multiple manual test cases, that is, parameterized or explicit cases.

    Often when writing tests, it's good practice to include specific known test cases (usually around boundaries).

    Currently, there seems to be these options:

    1. Manually write an individual test for each case. This works with one or a small number of boundaries, but becomes burdensome for any large number of similarly-structured cases.
    2. Use a macro to generate cases (or a crate that provides such a macro). This works, but generates additional methods under the covers. Failures refer to the failing line in the duplicated method, but picking the case out of the list may be hard in some cases. Too, this requires an additional crate, and almost certainly one that doesn't work with proptest.
    3. With proptest, use sample or uniform to select from a list of cases. At lower counts of cases, this should run all of them. However, this is really a misuse of those methods, and may end up confusing the engine besides. Additionally, it can be hard to spot which test case is failing with large manual lists. (4. Might be possible to add manual cases to the regression files? Haven't tried, but this seems like even more of a hack, and that you're more likely to lose cases when tests change)

    What I'd like is some way to provide explicit, multiple, test cases, in addition to the ones generated by proptest. All cases should be run (as opposed to only being maybe run, as with sample/uniform). Simplification scenarios would likely need to ignore the cases (especially for composed strategies), but being able to consider them as "known good" data would be a bonus. Ideally, it would also be possible to trace back to which manual case failed (eg, a line number, in addition to the data).

    opened by Clockwork-Muse 1
  • Improve float range sampling

    Improve float range sampling

    The current implementation has the flaw that it doesn't sample all the floating point values in the range. For example sampling from the f32 range [0.0, 16777216.0] will never generate any value with a fractional part even through around most of the floating point values in this range have fractional parts.

    This pull request addresses this by using a new algorithm that doesn't have that issue.

    opened by mikerite 0
  • Generating sorted sequences

    Generating sorted sequences

    What's the best way to generate sorted sequences of elements (integers, in my case)? The naive approach is just

    vec(element(), size).prop_map(|mut vec| {
        vec.sort();
        vec
    })
    

    but that's very sub-optimal in terms of shrinkage, is there a better approach?

    opened by Kixiron 2
Releases(0.9.6)
Owner
Jason Lingle
Jason Lingle
A minimalist property-based testing library based on the arbitrary crate.

A minimalist property-based testing library based on the arbitrary crate.

Aleksey Kladov 61 Dec 21, 2022
Testing Framework for Rust

Polish Polish is Test-Driven Development done right Getting Started Installing the Package The crates.io package is kept up-to-date with all the major

Fadi Hanna Al-Kass 49 Dec 18, 2022
ArchTest is a rule based architecture testing tool for rust

ArchTest is a rule based architecture testing tool. It applies static analyses on the specified rust project to extract use relationships.

Tom Dymel 7 Sep 26, 2021
Simple goldenfile testing in Rust.

?? Rust Goldenfile Simple goldenfile testing in Rust. Goldenfile tests generate one or more output files as they run. At the end of the test, the gene

Calder Coalson 24 Nov 26, 2022
Cucumber testing framework for Rust. Fully native, no external test runners or dependencies.

An implementation of the Cucumber testing framework for Rust. Fully native, no external test runners or dependencies.

Brendan Molloy 394 Jan 1, 2023
Loom is a concurrency permutation testing tool for Rust.

Loom is a testing tool for concurrent Rust code

Tokio 1.4k Jan 9, 2023
Drill is an HTTP load testing application written in Rust inspired by Ansible syntax

Drill is an HTTP load testing application written in Rust inspired by Ansible syntax

Ferran Basora 1.5k Jan 1, 2023
assay - A super powered testing macro for Rust

assay - A super powered testing macro for Rust as·say /ˈaˌsā,aˈsā/ noun - the testing of a metal or ore to determine its ingredients and quality. Rust

Michael Gattozzi 105 Dec 4, 2022
Rust testing library

K9 - Rust Testing Library Snapshot testing + better assertions Available test macros snapshot assert_equal assert_greater_than assert_greater_than_or_

Aaron Abramov 269 Dec 10, 2022
Testing Framework for Rust

Polish Polish is Test-Driven Development done right Getting Started Installing the Package The crates.io package is kept up-to-date with all the major

Fadi Hanna Al-Kass 49 Dec 18, 2022
Rustress - stress testing library in Rust. For fun

rustress Simple network stress testing library. To get familiar with Rust Planned features (Subject to change) Multithreaded client/server Throughput

Hakan Sönmez 7 Sep 22, 2022
insta: a snapshot testing library for Rust

insta: a snapshot testing library for Rust Introduction Snapshots tests (also sometimes called approval tests) are tests that assert values against a

Armin Ronacher 1.4k Jan 1, 2023
Rnp - A simple cloud-friendly tool for testing network reachability.

Rnp - A simple cloud-friendly tool for testing network reachability. Release Status Crates.io Github release Nuget packages NOTE: This project is in e

Riff 50 Dec 13, 2022
Simple assertion library for unit testing in python with a fluent API

Simple assertions library for unit testing in Python with a nice fluent API. Supports both Python 2 and 3.

snakedye 19 Sep 10, 2022
Viceroy provides local testing for developers working with Compute@Edge.

Viceroy provides local testing for developers working with Compute@Edge. It allows you to run services written against the Compute@Edge APIs on your local development machine, and allows you to configure testing backends for your service to communicate with.

Fastly 99 Jan 7, 2023
Declarative Testing Framework

Demonstrate allows tests to be written without as a much repetitive code within the demonstrate! macro, which will generate the corresponding full tests.

Austin Baugh 41 Aug 17, 2022
🧵 Generate self-describing strings of a given length to help aid software testing

rust-counter-strings Counter strings generator written in rust to help aid software testing What is a counterstring? "A counterstring is a graduated s

Thomas Chaplin 23 Jun 24, 2022
🔥 Unit testing framework for Subgraph development on The Graph protocol. ⚙️

?? Welcome to Matchstick - a unit testing framework for The Graph protocol. Try out your mapping logic in a sandboxed environment and ensure your hand

null 157 Dec 20, 2022
This is a tiny (but delightful!) utility library for exhaustive testing.

Exhaustigen This is a tiny (but delightful!) utility library for exhaustive testing. It is based (directly) on the idea and code in the following blog

Graydon Hoare 34 Dec 14, 2022