Unlock the Power of Property-Based Testing in Rust

When it comes to software testing, methodologies and techniques vary greatly in their practicality and effectiveness. In this article, we’ll delve into the world of property-based testing (PBT) and explore how it can be applied in Rust.

What is Property-Based Testing?

To illustrate how PBT works, let’s consider a basic unit test. Imagine you’ve written a function, maybe_works, that you want to compare against a function you know works properly, definitely_works. A unit test comparing these two functions for some input would look like this:

But there’s a catch. You need to know exactly which inputs to use in your tests to alert you to the presence of bugs. This becomes tedious if you want to test maybe_works against definitely_works for a variety of inputs.

A More Efficient Approach

A more efficient way to test maybe_works against definitely_works would be to run the test several times with a variety of randomly generated inputs. With these randomly generated inputs, you don’t know the precise value being supplied to maybe_works or definitely_works, but you can often make a general statement, such as “the outputs of maybe_works and definitely_works should be the same given the same input.”

Getting Started with Proptest

Let’s create a new Cargo project called sentence-parser. We’ll use the pest crate to write the parser, so add pest to your Cargo.toml. Create a file called sentence.pest and put it in the src directory.

The pest crate generates a parser from a user-defined grammar file, so we’ll define a grammar file that tells pest how to parse a certain type of input.

Writing a Parser with Proptest

Now that we have our grammar file set up, let’s write a parser using proptest. We’ll start by creating a strategy that produces a valid word.

Next, we’ll create a test that attempts to parse the generated word using the Rule::word rule.

Testing the Parser

Now that we have our parser set up, let’s test it with some invalid inputs. We’ll create a test that feeds non-letter characters to the parser as well as strings of length zero.

Building on the Words Rule

Next, we’ll create a words rule that matches sequences of words joined by spaces. We’ll follow the same pattern as before to test whether we’ve created a good rule.

Enclosed Rule

Now we’re going to build on the words rule by creating an enclosed rule that simply wraps a words in some kind of delimiter, such as commas or parentheses.

Chunk Rule

The words and enclosed rules are similar in the sense that they both represent sequences of words. To encode this similarity, we’ll make a chunk rule that matches either words or enclosed.

Punctuation Rule

Since sentences end with punctuation, let’s create a rule that matches punctuation.

Sentence Rule

It’s finally time to put it all together into a sentence rule. The SOI and EOI in this rule make sure the entire input is parsed, so inputs like a b c.def aren’t valid sentences.

Conclusion

At this point, you should have a passing understanding of how to write property-based tests. PBT isn’t always the answer, but the simple act of thinking about the abstract properties of your code can help you better understand it.

Want to learn more about LogRocket and how it can help you debug your Rust applications? Check out our article on Full Visibility into Web Frontends for Rust Apps.

Leave a Reply

Your email address will not be published. Required fields are marked *