Arbitraries
Arbitraries are components that generate data and perform shrinking, which are especially crucial elements in property-based testing.
In this document, the values handled by arbitraries are referred to as follows:
Example: A value generated by an arbitrary
Counterexample: A value that causes the test to fail
Shrunk: A value generated during the shrinking process
Falsifying example: The minimal value discovered through shrinking
Basic data types
Arbitraries that generate values of basic data types.
null_
Generates null
.
Examples from this arbitrary will never be shrunk.
boolean
Generates either true
or false
.
Examples from this arbitrary will never be shrunk.
integer
Generates integers between min
and max
. If no range is specified, it generates integers from the minimum to the maximum value of int
.
Examples from this arbitrary will be shrunk towards zero. Negative numbers are not shrunk.
float
Generates floating-point numbers between min
and max
. If no range is specified, it generates floating-point numbers from the minimum to the maximum value of double
.
If minExcluded
and maxExcluded
are true, the generated values will exclude the minimum and maximum values.
If nan
is true, it also generates NaN.
If infinity
is true, it also generates infinity.
Examples from this arbitrary will be shrunk towards zero. Negative numbers are not shrunk.
binary
Generates binary data (a list of integers ranging from 0 to 255) of lengths between min
and max
. If no range is specified, it generates binary data of lengths from 0 to 100.
Examples from this arbitrary will be shrunk towards the empty list.
Strings
runes
Generates runes with lengths ranging from min
to max
. If no range is specified, it generates runes with lengths from 0 to 100.
The character types for the generated runes can be specified using characterSet
.
Examples from this arbitrary will be shrunk towards empty runes.
string
Generates strings with lengths ranging from min
to max
. If no range is specified, it generates strings with lengths from 0 to 100.
The character types for the generated strings can be specified using characterSet
.
Examples from this arbitrary will be shrunk towards the empty string.
CharacterSet
CharacterSet
is a set of Unicode characters used to specify the characters to be generated in runes
and string
.
CharacterSet
allows you to specify:
Character encodings (ASCII, UTF-8, UTF-16)
Specific characters or code points
Unicode categories
For further details, refer to the API reference.
Collections
Arbitraries that generate lists, maps, and sets.
list
Generates a list containing elements produced by the element
arbitrary. The length of the list can be specified within the range from minLength
to maxLength
. If no range is specified, lists of lengths from 0 to 10 are generated.
If unique
is true, the elements of the list will not have duplicates. The comparison between elements is performed using ==
. Removed duplicates are not replenished, so the list's length may fall below minLength
.
If uniqueBy
is specified, the elements of the list are compared using the function provided by uniqueBy
.
Examples from this arbitrary will be shrunk towards the empty list.
map
Generates a map with keys and values produced by the key
and value
arbitraries, respectively. The length of the map can be specified within the range from minLength
to maxLength
. If no range is specified, maps of lengths from 0 to 10 are generated.
Examples from this arbitrary will be shrunk towards the empty map.
set
Generates a set containing elements produced by the element
arbitrary. The length of the set can be specified within the range from minLength
to maxLength
. If no range is specified, sets of lengths from 0 to 10 are generated.
Examples from this arbitrary will be shrunk towards the empty set.
Dates and times
Arbitraries that generate date and time values. There are no arbitraries that generate only time; if only time is needed, use dateTime
and ignore the date component.
dateTime
Generates datetime values between min
and max
. If no range is specified, it generates datetime values from January 1, 0000, 00:00:00 to December 31, 9999, 23:59:59.
The generated values are of the TZDateTime
type from the package:timezone
. Dart's DateTime
does not hold timezone information other than local time and UTC, hence the use of package:timezone
. TZDateTime
is compatible with DateTime
, so it can be used in the same way.
If location
is specified, datetime is generated in that timezone. If not specified, local time is generated.
The DateTime
specified in min
and max
purely uses the time component, and the timezone of the DateTime
is ignored.
Examples from this arbitrary will be shrunk towards midnight on January 1st, 2000, local time.
nominalDateTime
Generates datetime values between min
and max
. If no range is specified, it generates datetime values from January 1, 0000, 00:00:00 to December 31, 9999, 23:59:59. The basic behavior is the same as dateTime
.
The differences from dateTime
are as follows:
If
imaginary
is set totrue
, it can generate imaginary datetime (fictional dates).Returns
NominalDateTime
instead ofDateTime
.
Imaginary dates refer to dates that do not actually exist, such as February 29th in a non-leap year or the 31st of a month that does not have 31 days. Currently, the generation of non-existent times occurring at the start and end times of daylight saving time is not implemented.
NominalDateTime
is an object that holds the date and time exactly as numerically represented. Unlike DateTime
, it does not validate for authenticity, so it can hold imaginary dates as they are. It can be converted to TZDateTime
using toTZDateTime
, but imaginary dates are converted to real time. The conversion method depends on TZDateTime
.
Constant values
Arbitraries that generate constant values.
constant
Generates only the value
. Be cautious if passing mutable objects as value
is not copied.
Examples from this arbitrary will never be shrunk.
constantFrom
Randomly selects and generates one item from values
. Be cautious as values are not copied, which is important if mutable objects are used.
Examples from this arbitrary will never be shrunk.
Composition
Arbitraries that can combine multiple arbitraries.
combine
Various combine
functions generate values as record simultaneously from multiple arbitraries. You can combine 2 to 8 arbitraries.
If you want to process the generated data before passing it to the test block, you should use map
.
Example: Generating a Point
from two integers
Shrinking is done sequentially for each arbitrary.
oneOf
Randomly selects and generates a value from arbitraries
in each iteration.
Shrinking is performed on the value that caused an error. No other arbitraries that did not generate this value are used for shrinking.
frequency
Randomly selects and generates a value from arbitraries
in each iteration, where the first element of each record in arbitraries
is the weight. The probability of selecting each arbitrary is proportional to its weight relative to the total weight.
Example:
Shrinking is performed on the value that caused an error. No other arbitraries that did not generate this value are used for shrinking.
recursive
Generates values for recursive data structures.
base
is a function that returns the base case arbitrary, which is executed first. extend
is a function that returns an arbitrary for extending the recursion, taking as an argument the value generated by the base
or the previous extend
.
maxDepth
is the maximum depth of recursion. The default is 5. Increasing the depth of recursion can significantly increase the time required for data generation.
Example: Generating a recursive list of integers
Shrinking first occurs within the generated arbitrary. Then, the depth is reduced by one, and the arbitrary is regenerated to use the values it generates. This alternates until the depth reaches zero.
deck
This arbitrary itself does not generate specific values but creates a Deck
that can generate values using any arbitrary. In the test block, specifying any arbitrary as an argument to Deck.draw
will generate values using that arbitrary. See also Interactive generation.
Shrinking is performed on the value that caused an error. No other arbitraries that did not generate this value are used for shrinking.
build
Generates a value using the provided builder.
Examples from this arbitrary will never be shrunk.
Example manipulation
Methods to manipulate values generated by arbitraries.
Transform examples
The map
method allows transforming values generated by an arbitrary. The definition of map
is as follows:
The following example generates a queue from the generated list.
Even without using map
, a queue can be generated within the test block using a list generated by list(integer())
. The difference with map
is that map
creates a new arbitrary, which can be combined with other arbitraries.
Shrinking is performed on the value before transformation.
Create new arbitraries from examples
The flatMap
method allows for the creation of new arbitraries using the values generated by another arbitrary. The definition of flatMap
is as follows:
The example below creates an arbitrary that generates lists with a minimum length determined by the generated integer.
Shrinking is performed by the generated arbitrary.
Filter examples
The filter
method allows for the generation of values that only meet a certain condition. The definition of filter
is as follows:
The following example generates only even integers:
Generation continues until the maxExamples
is reached. However, if the number of generation attempts reaches maxTries
, it results in an error.
Shrinking is also performed only on values that meet the condition.
Interactive generation
Using deck
, values can be generated during the execution of the test block using any arbitrary.
Simple example: The following generates two integers during the test and creates a Point
. The same process can be written using combine
.
Complex example: Generates an integer and changes the next arbitrary to use based on whether the integer is even or odd.
Custom data types
Existing arbitraries can be combined to generate values for data types not directly supported by existing arbitraries.
For generating instances of data types that are derived from a single value or classes that only have one field, it's beneficial to transform the values generated by existing arbitraries using map
or flatMap
.
If multiple data points are needed, it's effective to use combine
to merge multiple arbitraries.
If there is a need to switch between arbitraries based on certain conditions during data generation, using deck
is advisable.
Generate values outside of tests
To generate values outside of tests, use the Arbitrary.example
method.
The arguments include RandomState
and whether to include edge cases. RandomState
is an object representing the state of the random number generator (including the seed), and duplicating it allows the same random numbers to be reproduced any number of times.
Examples from this arbitrary will never be shrunk.