Library / SDK
whatyouhide/stream_data avatar
whatyouhide/stream_data

StreamData gives Elixir tests a generator to argue with

Data generation and property-based testing for Elixir. 🔮

951 stars76 forksElixirLicense varies

At a glance

What is it?
StreamData is an Elixir library for data generation and property-based testing, where generators are ordinary enumerables and properties are written with a check all macro over generated values. The README is unusually candid about where it loses to PropCheck, namely stateful testing and stored counter-examples, and that candour is the most useful part of it.
Who is it for?
StreamData suits an Elixir team that wants property-based testing without leaving the language, and suits anyone who wants random data generation for fixtures or load experiments, since the generators are ordinary enumerables that work outside the test suite.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 45 days ago.
What is it written in?
Mainly Elixir, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Generators are Elixir enumerables

StreamData is an Elixir library for data generation and property-based testing, and the design decision that makes it pleasant is that generators are not a special type. They implement the Enumerable protocol, so they are infinite streams of data that you can treat like any other stream.

elixir
StreamData.integer() |> Stream.map(&abs/1) |> Enum.take(3)
#=> [1, 0, 2]

That single line contains the whole idea. There is no generator object with its own API, no run loop to learn, and no special syntax. A generator is something you pipe into Stream.map and then take three items from, and the library provides the functions to combine generators into new ones.

It matters because the same machinery then serves two purposes. The README describes StreamData as made of two main components, data generation and property-based testing, with the StreamData module providing the tools for generation and the ExUnitProperties module handling the property-based testing functionality.

The distinction is worth stating because it is unusual among testing libraries. The generator half is not locked inside the test framework. If you need a hundred thousand plausible records to seed a database, or a stream of values to fuzz a parser outside ExUnit, that is the same code path the property tests use.

This is also the specific reason the README gives for choosing StreamData over the Erlang alternatives, and it is a real difference rather than a marketing one. A generator that is an enumerable is usable from any Elixir code, not only from a test.

Custom generators are written with a macro, not a struct

Building a generator for your own domain is the step where a property-based test either becomes practical or does not, and StreamData handles it with a macro that looks like a comprehension.

elixir
require ExUnitProperties

domains = [
  "gmail.com",
  "hotmail.com",
  "yahoo.com",
]

email_generator =
  ExUnitProperties.gen all name <- StreamData.string(:alphanumeric),
                           name != "",
                           domain <- StreamData.member_of(domains) do
    name <> "@" <> domain
  end

Enum.take(StreamData.resize(email_generator, 20), 2)
#=> ["[email protected]", "[email protected]"]

Read it as a for-comprehension with guards. The gen all macro binds generated values, applies constraints such as name != "", and the block produces the output value. The constraints are the interesting part, because they let you exclude values that are uninteresting or degenerate before they reach your code.

The resize call is the other half of the ergonomics. It sets the size of the generated values, which for strings and lists means how long they are, and the README uses it to pull a handful of short examples out of a generator that can produce arbitrarily long values.

Everything else in the module follows the same shape. There is a generator for integers and one for strings with a character mode, member_of for choosing from a list, and combinators for building new generators out of existing ones. The claim in the README is that StreamData provides all the necessary tools to create arbitrarily complex custom generators, and the example above is the smallest case of that.

A property is a statement, not a fixture

The property-based testing half replaces hand written inputs and expected outputs with a statement that should hold across generated data.

The README describes the shift plainly. Property testing aims at randomizing test data so that tests cover cases you did not think to write by hand. Instead of writing a bunch of inputs and expected outputs by hand, with property-based testing you write a property of your code that should hold for a set of data, and then generate data in that set in attempt to falsify that property.

The syntax follows that definition closely:

elixir
use ExUnitProperties

property "bin1 <> bin2 always starts with bin1" do
  check all bin1 <- binary(),
            bin2 <- binary() do
    assert String.starts_with?(bin1 <> bin2, bin1)
  end
end

The check all macro binds each generated value and runs the body against them, so the assertion runs many times with different data rather than once with a fixed example. The property name is a string that appears in the test report, which matters more than it looks, because when a property fails the failing case is usually reported by that name.

The `use ExUnitProperties` line is what wires the property macro into ExUnit, so a property test sits in the same test files as ordinary tests and runs under the same runner.

The lineage is stated in the README too. The property-based testing side of the library is heavily inspired by the original QuickCheck paper, which targeted Haskell, as well as Clojure's take on property-based testing with test.check. Knowing that helps when you are looking for prior art or reading about shrinking strategies, since the vocabulary comes from that tradition.

A test-only dependency, with a formatter footnote

Installation is a dependency line and a fetch, which is the whole procedure.

elixir
defp deps() do
  [{:stream_data, "~> 1.0", only: :test}]
end

Then run mix deps.get. The README notes that StreamData is usually added only to the :test environment since it is used in tests and test data generation, which is the standard shape for a testing library.

There is one extra step that is easy to skip and that you will want anyway. To import StreamData's formatter configuration, add the :dev environment as well as :test for stream_data, and add :stream_data to your .formatter.exs:

elixir
[
  import_deps: [:stream_data]
]

That is about code formatting rather than testing, but it belongs in the setup notes because it is a one-time change to project configuration that the library expects if you want the formatting to be consistent with the library's own style.

The version constraint is ~> 1.0, which pins the library to the 1.x line. The package lives on hex.pm and the documentation is published on hexdocs.pm/stream_data, which is also the homepage given for the project.

Everything else in the repository follows the standard Elixir layout, with mix.exs, mix.lock, lib/, test/, a CHANGELOG.md and an examples/ directory whose examples_test.exs file demonstrates the library in use.

Where PropCheck wins, and where StreamData does

The README has a section titled differences from other property-based testing frameworks, and it is unusually direct for a library documenting its own competition.

There are a handful of property-based testing frameworks for the BEAM ecosystem, and for Elixir the main alternative to StreamData is PropCheck, which is a wrapper around PropEr, a property-based testing framework for Erlang. The README then lists the fundamental differences to help you choose between the two.

PropEr, through PropCheck, provides stateful property-based testing. If you need to test a system with state by building a model of the system to test against, you will have to go with PropCheck since StreamData does not support this yet. PropEr can also store counter-examples, while StreamData does not support storing counter-examples in a file, and you have to reuse the seed that caused the failure in order to reproduce it.

Those two are real gaps, and they are the reason to read this section before choosing.

StreamData's side of the ledger has two entries. It provides functionality for generating data as the base for property-based testing, and its generators can be used outside of property-based testing as normal Elixir streams that produce random data. And it is native to Elixir, written entirely in Elixir with an idiomatic API, where for example all generators are Elixir enumerables.

So the choice comes down to what your tests need. If the system under test has state and you want to model it, the answer is PropCheck today. If you want generators you can use anywhere in your Elixir codebase, and a property-based suite that runs in the language you already write, the answer is StreamData.

One caveat about the counter-example situation. Reproducing a failure by reusing the seed is workable, but it depends on the seed being reported and on the generator being deterministic for that seed. It is a weaker guarantee than a stored counter-example file, and it is worth checking how your test output presents the seed before you depend on it.

Maintenance, licence and the shape of the project

StreamData is a mature Elixir library rather than an experiment.

The repository is not archived and the last push was on 2026-09-08, about six weeks before this review. There are no GitHub releases, which is normal for a hex.pm package, where the published version is the version that matters and the CHANGELOG.md at the top level records the history. Continuous integration runs through a GitHub Actions workflow with a badge, and coverage is tracked through Coveralls.

The licence is the Apache License, Version 2.0, with copyright 2017 Andrea Leopardi and José Valim, and the full text is reproduced in the README. Apache 2.0 is a reasonable choice for a library that other people's test suites will depend on, since it is permissive and includes an explicit patent grant. Note that the licence metadata on the repository itself does not read as a standard SPDX identifier, so read the README text rather than relying on the badge.

The authorship is worth noting for context. José Valim is a long-standing figure in the Elixir community, and the library was announced on the Elixir website in 2017, with the announcement linked from the README. The project's origin in the official blog post is a good sign of long-term stewardship, and the version constraint of ~> 1.0 reflects a decade of compatible releases.

What is not changing is the scope. The README is clear that StreamData does not support stateful property-based testing yet, and there is no roadmap entry in the documentation that suggests that is about to change. If you adopt it, adopt it for what it does well, which is generating data and testing properties over plain values.

Editorial conclusion

StreamData suits an Elixir team that wants property-based testing without leaving the language, and suits anyone who wants random data generation for fixtures or load experiments, since the generators are ordinary enumerables that work outside the test suite. It is the wrong choice if you need stateful testing against a model of a stateful system, or if you need failing counter-examples saved to a file, because the README states plainly that StreamData does not support either and that PropCheck is the option in those cases. Before you adopt it, check how you will reproduce a failure, since the seed is the only handle you get, and decide whether the property-based model fits the bug you are hunting, since a property you cannot express is not made easier by a generator.

Frequently asked questions

How do I add StreamData to an Elixir project?

Add {:stream_data, "~> 1.0", only: :test} to your deps and run mix deps.get. To import the library's formatter configuration, add the :dev environment as well as :test and add :stream_data to the import_deps list in your .formatter.exs.

What is the difference between StreamData and PropCheck for Elixir?

The README lists the differences directly. PropEr through PropCheck provides stateful property-based testing and can store counter-examples, while StreamData does not support either yet. StreamData instead provides generators usable outside property-based testing as normal Elixir streams, and is written entirely in Elixir with an idiomatic API.

How do I reproduce a failing property test in StreamData?

StreamData does not support storing counter-examples in a file, so you have to reuse the seed that caused the failure in order to reproduce it. If you need stored counter-examples, the README points to PropCheck as the option that supports it.

Can I use StreamData generators outside of tests?

Yes. StreamData generators implement the Enumerable protocol and can be used as normal Elixir streams that produce random data, so the same generation code can feed fixtures or other tooling as well as property tests.

What licence does StreamData use?

The README states the Apache License, Version 2.0, with copyright 2017 Andrea Leopardi and José Valim. The package is published on hex.pm and the documentation is at hexdocs.pm/stream_data.

Official sources

  1. Issues
  2. Project website
  3. README
  4. whatyouhide/stream_data on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/whatyouhide-stream-data.svg)](https://hysenlabs.com/projects/whatyouhide-stream-data)

Was this useful?