Documentation ¶
Overview ¶
Package gopter contain the main interfaces of the GOlang Property TestER.
A simple property test might look like this:
func TestSqrt(t *testing.T) { properties := gopter.NewProperties(nil) properties.Property("greater one of all greater one", prop.ForAll( func(v float64) bool { return math.Sqrt(v) >= 1 }, gen.Float64Range(1, math.MaxFloat64), )) properties.Property("squared is equal to value", prop.ForAll( func(v float64) bool { r := math.Sqrt(v) return math.Abs(r*r-v) < 1e-10*v }, gen.Float64Range(0, math.MaxFloat64), )) properties.TestingRun(t) }
Generally a property is just a function that takes GenParameters and produces a PropResult:
type Prop func(*GenParameters) *PropResult
but usually you will use prop.ForAll, prop.ForAllNoShrink or arbitrary.ForAll. There is also the commands package, which can be helpful for stateful testing.
Example (Fizzbuzz) ¶
package main import ( "errors" "math" "strconv" "strings" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" ) // Fizzbuzz: See https://wikipedia.org/wiki/Fizz_buzz func fizzbuzz(number int) (string, error) { if number <= 0 { return "", errors.New("Undefined") } switch { case number%15 == 0: return "FizzBuzz", nil case number%3 == 0: return "Fizz", nil case number%5 == 0: return "Buzz", nil } return strconv.Itoa(number), nil } func main() { properties := gopter.NewProperties(nil) properties.Property("Undefined for all <= 0", prop.ForAll( func(number int) bool { result, err := fizzbuzz(number) return err != nil && result == "" }, gen.IntRange(math.MinInt32, 0), )) properties.Property("Start with Fizz for all multiples of 3", prop.ForAll( func(i int) bool { result, err := fizzbuzz(i * 3) return err == nil && strings.HasPrefix(result, "Fizz") }, gen.IntRange(1, math.MaxInt32/3), )) properties.Property("End with Buzz for all multiples of 5", prop.ForAll( func(i int) bool { result, err := fizzbuzz(i * 5) return err == nil && strings.HasSuffix(result, "Buzz") }, gen.IntRange(1, math.MaxInt32/5), )) properties.Property("Int as string for all non-divisible by 3 or 5", prop.ForAll( func(number int) bool { result, err := fizzbuzz(number) if err != nil { return false } parsed, err := strconv.ParseInt(result, 10, 64) return err == nil && parsed == int64(number) }, gen.IntRange(1, math.MaxInt32).SuchThat(func(v interface{}) bool { return v.(int)%3 != 0 && v.(int)%5 != 0 }), )) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) }
Output: + Undefined for all <= 0: OK, passed 100 tests. + Start with Fizz for all multiples of 3: OK, passed 100 tests. + End with Buzz for all multiples of 5: OK, passed 100 tests. + Int as string for all non-divisible by 3 or 5: OK, passed 100 tests.
Example (Labels) ¶
Example_labels demonstrates how labels may help, in case of more complex conditions. The output will be:
! Check spooky: Falsified after 0 passed tests. > Labels of failing property: even result a: 3 a_ORIGINAL (44 shrinks): 861384713 b: 0 b_ORIGINAL (1 shrinks): -642623569
package main import ( "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" ) func spookyCalculation(a, b int) int { if a < 0 { a = -a } if b < 0 { b = -b } return 2*b + 3*(2+(a+1)+b*(b+1)) } // Example_labels demonstrates how labels may help, in case of more complex // conditions. // The output will be: // // ! Check spooky: Falsified after 0 passed tests. // > Labels of failing property: even result // a: 3 // a_ORIGINAL (44 shrinks): 861384713 // b: 0 // b_ORIGINAL (1 shrinks): -642623569 func main() { parameters := gopter.DefaultTestParameters() parameters.Rng.Seed(1234) // Just for this example to generate reproducible results parameters.MinSuccessfulTests = 10000 properties := gopter.NewProperties(parameters) properties.Property("Check spooky", prop.ForAll( func(a, b int) string { result := spookyCalculation(a, b) if result < 0 { return "negative result" } if result%2 == 0 { return "even result" } return "" }, gen.Int().WithLabel("a"), gen.Int().WithLabel("b"), )) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) }
Output: ! Check spooky: Falsified after 0 passed tests. > Labels of failing property: even result a: 3 a_ORIGINAL (44 shrinks): 861384713 b: 0 b_ORIGINAL (1 shrinks): -642623569
Example (Libraries) ¶
package main import ( "reflect" "github.com/leanovate/gopter" "github.com/leanovate/gopter/arbitrary" "github.com/leanovate/gopter/gen" ) type TestBook struct { Title string Content string } func genTestBook() gopter.Gen { return gen.Struct(reflect.TypeOf(&TestBook{}), map[string]gopter.Gen{ "Title": gen.AlphaString(), "Content": gen.AlphaString(), }) } type TestLibrary struct { Name string Librarians uint8 Books []TestBook } func genTestLibrary() gopter.Gen { return gen.Struct(reflect.TypeOf(&TestLibrary{}), map[string]gopter.Gen{ "Name": gen.AlphaString().SuchThat(func(s string) bool { return s != "" }), "Librarians": gen.UInt8Range(1, 255), "Books": gen.SliceOf(genTestBook()), }) } type CityName = string type TestCities struct { Libraries map[CityName][]TestLibrary } func genTestCities() gopter.Gen { return gen.StructPtr(reflect.TypeOf(&TestCities{}), map[string]gopter.Gen{ "Libraries": (gen.MapOf(gen.AlphaString(), gen.SliceOf(genTestLibrary()))), }) } func main() { parameters := gopter.DefaultTestParameters() parameters.Rng.Seed(1234) // Just for this example to generate reproducible results parameters.MaxSize = 5 arbitraries := arbitrary.DefaultArbitraries() arbitraries.RegisterGen(genTestCities()) properties := gopter.NewProperties(parameters) properties.Property("no unsupervised libraries", arbitraries.ForAll( func(tc *TestCities) bool { for _, libraries := range tc.Libraries { for _, library := range libraries { if library.Librarians == 0 { return false } } } return true }, )) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) }
Output: + no unsupervised libraries: OK, passed 100 tests.
Example (Libraries2) ¶
package main import ( "github.com/leanovate/gopter" "github.com/leanovate/gopter/arbitrary" "github.com/leanovate/gopter/gen" ) type TestBook struct { Title string Content string } type TestLibrary struct { Name string Librarians uint8 Books []TestBook } type CityName = string type TestCities struct { Libraries map[CityName][]TestLibrary } func main() { parameters := gopter.DefaultTestParameters() parameters.Rng.Seed(1234) // Just for this example to generate reproducible results arbitraries := arbitrary.DefaultArbitraries() // All string are alphanumeric arbitraries.RegisterGen(gen.AlphaString()) properties := gopter.NewProperties(parameters) properties.Property("libraries always empty", arbitraries.ForAll( func(tc *TestCities) bool { return len(tc.Libraries) == 0 }, )) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) }
Output: ! libraries always empty: Falsified after 2 passed tests. ARG_0: &{Libraries:map[z:[]]}
Example (Panic) ¶
package main import ( "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" ) func main() { parameters := gopter.DefaultTestParameters() parameters.Rng.Seed(1234) // Just for this example to generate reproducible results properties := gopter.NewProperties(parameters) properties.Property("Will panic", prop.ForAll( func(i int) bool { if i%2 == 0 { panic("hi") } return true }, gen.Int().WithLabel("number"))) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) }
Output: ! Will panic: Error on property evaluation after 6 passed tests: Check paniced: hi number: 0 number_ORIGINAL (1 shrinks): 2015020988
Example (Sqrt) ¶
package main import ( "math" "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" ) func main() { parameters := gopter.DefaultTestParameters() parameters.Rng.Seed(1234) // Just for this example to generate reproducible results properties := gopter.NewProperties(parameters) properties.Property("greater one of all greater one", prop.ForAll( func(v float64) bool { return math.Sqrt(v) >= 1 }, gen.Float64().SuchThat(func(x float64) bool { return x >= 1.0 }), )) properties.Property("squared is equal to value", prop.ForAll( func(v float64) bool { r := math.Sqrt(v) return math.Abs(r*r-v) < 1e-10*v }, gen.Float64().SuchThat(func(x float64) bool { return x >= 0.0 }), )) // When using testing.T you might just use: properties.TestingRun(t) properties.Run(gopter.ConsoleReporter(false)) }
Output: + greater one of all greater one: OK, passed 100 tests. + squared is equal to value: OK, passed 100 tests.
Index ¶
- Constants
- Variables
- func NewLockedSource(seed int64) *lockedSource
- type BiMapper
- type Flag
- type FormatedReporter
- type Gen
- func (g Gen) FlatMap(f func(interface{}) Gen, resultType reflect.Type) Gen
- func (g Gen) Map(f interface{}) Gen
- func (g Gen) MapResult(f func(*GenResult) *GenResult) Gen
- func (g Gen) Sample() (interface{}, bool)
- func (g Gen) SuchThat(f interface{}) Gen
- func (g Gen) WithLabel(label string) Gen
- func (g Gen) WithShrinker(shrinker Shrinker) Gen
- type GenParameters
- type GenResult
- type Prop
- type PropArg
- type PropArgs
- type PropResult
- type Properties
- type Reporter
- type Shrink
- type Shrinker
- type TestParameters
- type TestResult
Examples ¶
Constants ¶
const ( // PropProof THe property was proved (i.e. it is known to be correct and will be always true) PropProof propStatus = iota // PropTrue The property was true this time PropTrue // PropFalse The property was false this time PropFalse // PropUndecided The property has no clear outcome this time PropUndecided // PropError The property has generated an error PropError )
const ( // TestPassed indicates that the property check has passed. TestPassed testStatus = iota // TestProved indicates that the property has been proved. TestProved // TestFailed indicates that the property check has failed. TestFailed // TestExhausted indicates that the property check has exhausted, i.e. the generators have // generated too many empty results. TestExhausted // TestError indicates that the property check has finished with an error. TestError )
Variables ¶
var ( // DefaultGenParams can be used as default für *GenParameters DefaultGenParams = DefaultGenParameters() MinGenParams = MinGenParameters() )
var NoShrink = Shrink(func() (interface{}, bool) { return nil, false })
NoShrink is an empty shrink.
var NoShrinker = Shrinker(func(value interface{}) Shrink { return NoShrink })
NoShrinker is a shrinker for NoShrink, i.e. a Shrinker that will not shrink any values. This is the default Shrinker if none is provided.
Functions ¶
func NewLockedSource ¶ added in v0.2.2
func NewLockedSource(seed int64) *lockedSource
NewLockedSource takes a seed and returns a new lockedSource for use with rand.New
Types ¶
type BiMapper ¶
type BiMapper struct { UpTypes []reflect.Type DownTypes []reflect.Type Downstream reflect.Value Upstream reflect.Value }
BiMapper is a bi-directional (or bijective) mapper of a tuple of values (up) to another tuple of values (down).
func NewBiMapper ¶
func NewBiMapper(downstream interface{}, upstream interface{}) *BiMapper
NewBiMapper creates a BiMapper of two functions `downstream` and its inverse `upstream`. That is: The return values of `downstream` must match the parameters of `upstream` and vice versa.
func (*BiMapper) ConvertDown ¶
func (b *BiMapper) ConvertDown(up []interface{}) []interface{}
ConvertDown calls the Downstream function on the elements of the up array and returns the results.
type Flag ¶
type Flag struct {
// contains filtered or unexported fields
}
Flag is a convenient helper for an atomic boolean
type FormatedReporter ¶
type FormatedReporter struct {
// contains filtered or unexported fields
}
FormatedReporter reports test results in a human readable manager.
func (*FormatedReporter) ReportTestResult ¶
func (r *FormatedReporter) ReportTestResult(propName string, result *TestResult)
ReportTestResult reports a single property result
type Gen ¶
type Gen func(*GenParameters) *GenResult
Gen generator of arbitrary values. Usually properties are checked by verifing a condition holds true for arbitrary input parameters generated by a Gen.
IMPORTANT: Even though a generator is supposed to generate random values, it should do this in a reproducible way. Therefore a generator has to create the same result for the same GenParameters, i.e. ensure that you just use the RNG provided by GenParameters and no external one. If you just plug generators together you do not have to worry about this.
func CombineGens ¶
CombineGens creates a generators from a list of generators. The result type will be a []interface{} containing the generated values of each generators in the list. Note: The combined generator will not have a sieve or shrinker.
func DeriveGen ¶
DeriveGen derives a generator with shrinkers from a sequence of other generators mapped by a bijective function (BiMapper)
func (Gen) FlatMap ¶
FlatMap creates a derived generator by passing a generated value to a function which itself creates a generator.
func (Gen) Map ¶
Map creates a derived generators by mapping all generatored values with a given function. f: has to be a function with one parameter (matching the generated value) and a single return. Note: The derived generator will not have a sieve or shrinker. Note: The mapping function may have a second parameter "*GenParameters" Note: The first parameter of the mapping function and its return may be a *GenResult (this makes MapResult obsolete)
func (Gen) MapResult ¶
MapResult creates a derived generator by mapping the GenResult directly. Contrary to `Map` and `FlatMap` this also allow the conversion of shrinkers and sieves, but implementation is more cumbersome. Deprecation note: Map now has the same functionality
func (Gen) Sample ¶
Sample generate a sample value. Depending on the state of the RNG the generate might fail to provide a sample
func (Gen) SuchThat ¶
SuchThat creates a derived generator by adding a sieve. f: has to be a function with one parameter (matching the generated value) returning a bool. All generated values are expected to satisfy
f(value) == true.
Use this care, if the sieve to to fine the generator will have many misses which results in an undecided property.
func (Gen) WithLabel ¶
WithLabel adds a label to a generated value. Labels are usually used for reporting for the arguments of a property check.
func (Gen) WithShrinker ¶
WithShrinker creates a derived generator with a specific shrinker
type GenParameters ¶
GenParameters encapsulates the parameters for all generators.
func DefaultGenParameters ¶
func DefaultGenParameters() *GenParameters
DefaultGenParameters creates default GenParameters.
func MinGenParameters ¶ added in v0.2.4
func MinGenParameters() *GenParameters
MinGenParameters creates minimal GenParameters. Note: Most likely you do not want to use these for actual testing
func (*GenParameters) CloneWithSeed ¶
func (p *GenParameters) CloneWithSeed(seed int64) *GenParameters
CloneWithSeed clone the current parameters with a new seed. This is useful to create subsections that can rerun (provided you keep the seed)
func (*GenParameters) NextBool ¶
func (p *GenParameters) NextBool() bool
NextBool create a random boolean using the underlying Rng.
func (*GenParameters) NextInt64 ¶
func (p *GenParameters) NextInt64() int64
NextInt64 create a random int64 using the underlying Rng.
func (*GenParameters) NextUint64 ¶
func (p *GenParameters) NextUint64() uint64
NextUint64 create a random uint64 using the underlying Rng.
func (*GenParameters) WithSize ¶
func (p *GenParameters) WithSize(size int) *GenParameters
WithSize modifies the size parameter. The size parameter defines an upper bound for the size of generated slices or strings.
type GenResult ¶
type GenResult struct { Labels []string Shrinker Shrinker ResultType reflect.Type Result interface{} Sieve func(interface{}) bool }
GenResult contains the result of a generator.
func NewEmptyResult ¶
NewEmptyResult creates an empty generator result. Unless the sieve does not explicitly allow it, empty (i.e. nil-valued) results are considered invalid.
func NewGenResult ¶
NewGenResult creates a new generator result from for a concrete value and shrinker. Note: The concrete value "result" not be nil
func (*GenResult) Retrieve ¶
Retrieve gets the concrete generator result. If the result is invalid or does not pass the sieve there is no concrete value and the property using the generator should be undecided.
func (*GenResult) RetrieveAsValue ¶
RetrieveAsValue get the concrete generator result as reflect value. If the result is invalid or does not pass the sieve there is no concrete value and the property using the generator should be undecided.
type Prop ¶
type Prop func(*GenParameters) *PropResult
Prop represent some kind of property that (drums please) can and should be checked
func (Prop) Check ¶
func (prop Prop) Check(parameters *TestParameters) *TestResult
Check the property using specific parameters
type PropArg ¶
PropArg contains information about the specific values for a certain property check. This is mostly used for reporting when a property has falsified.
func NewPropArg ¶
NewPropArg creates a new PropArg.
type PropResult ¶
type PropResult struct { Status propStatus Error error ErrorStack []byte Args []*PropArg Labels []string }
PropResult contains the result of a property
func NewPropResult ¶
func NewPropResult(success bool, label string) *PropResult
NewPropResult create a PropResult with label
func (*PropResult) AddArgs ¶
func (r *PropResult) AddArgs(args ...*PropArg) *PropResult
AddArgs add argument descriptors to the PropResult for reporting
func (*PropResult) And ¶
func (r *PropResult) And(other *PropResult) *PropResult
And combines two PropResult by an and operation. The resulting PropResult will be only true if both PropResults are true.
func (*PropResult) Success ¶
func (r *PropResult) Success() bool
Success checks if the result was successful
func (*PropResult) WithArgs ¶
func (r *PropResult) WithArgs(args []*PropArg) *PropResult
WithArgs sets argument descriptors to the PropResult for reporting
type Properties ¶
type Properties struct {
// contains filtered or unexported fields
}
Properties is a collection of properties that should be checked in a test
func NewProperties ¶
func NewProperties(parameters *TestParameters) *Properties
NewProperties create new Properties with given test parameters. If parameters is nil default test parameters will be used
func (*Properties) Property ¶
func (p *Properties) Property(name string, prop Prop)
Property add/defines a property in a test.
func (*Properties) Run ¶
func (p *Properties) Run(reporter Reporter) bool
Run checks all definied propertiesand reports the result
func (*Properties) TestingRun ¶
func (p *Properties) TestingRun(t *testing.T, opts ...interface{})
TestingRun checks all definied properties with a testing.T context. This the preferred wait to run property tests as part of a go unit test.
type Reporter ¶
type Reporter interface { // ReportTestResult reports a single property result ReportTestResult(propName string, result *TestResult) }
Reporter is a simple interface to report/format the results of a property check.
func ConsoleReporter ¶
ConsoleReporter creates a FormatedReporter writing to the console (i.e. stdout)
func NewFormatedReporter ¶
NewFormatedReporter create a new formated reporter verbose toggles verbose output of the property results width is the maximal width per line output is the writer were the report will be written to
type Shrink ¶
type Shrink func() (interface{}, bool)
Shrink is a stream of shrunk down values. Once the result of a shrink is false, it is considered to be exhausted. Important notes for implementors:
- Ensure that the returned stream is finite, even though shrinking will eventually be aborted, infinite streams may result in very slow running test.
- Ensure that modifications to the returned value will not affect the internal state of your Shrink. If in doubt return by value not by reference
func ConcatShrinks ¶
ConcatShrinks concats an array of shrinks to a single shrinks
func (Shrink) All ¶
func (s Shrink) All() []interface{}
All collects all shrinks as a slice. Use with care as this might create large results depending on the complexity of the shrink
func (Shrink) Interleave ¶
Interleave this shrink with another Both shrinks are expected to produce the same result
type Shrinker ¶
type Shrinker func(value interface{}) Shrink
Shrinker creates a shrink for a given value
func CombineShrinker ¶
CombineShrinker create a shrinker by combining a list of shrinkers. The resulting shrinker will shrink an []interface{} where each element will be shrunk by the corresonding shrinker in 'shrinkers'. This method is implicitly used by CombineGens.
type TestParameters ¶
type TestParameters struct { MinSuccessfulTests int // MinSize is an (inclusive) lower limit on the size of the parameters MinSize int // MaxSize is an (exclusive) upper limit on the size of the parameters MaxSize int MaxShrinkCount int Seed int64 Rng *rand.Rand Workers int MaxDiscardRatio float64 }
TestParameters to run property tests
func DefaultTestParameters ¶
func DefaultTestParameters() *TestParameters
DefaultTestParameterWithSeeds creates reasonable default Parameters for most cases with an undefined RNG-seed
func DefaultTestParametersWithSeed ¶ added in v0.2.2
func DefaultTestParametersWithSeed(seed int64) *TestParameters
DefaultTestParameterWithSeeds creates reasonable default Parameters for most cases based on a fixed RNG-seed
type TestResult ¶
type TestResult struct { Status testStatus Succeeded int Discarded int Labels []string Error error ErrorStack []byte Args PropArgs Time time.Duration }
TestResult contains the result of a property property check.
func (*TestResult) Passed ¶
func (r *TestResult) Passed() bool
Passed checks if the check has passed
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
Package arbitrary contains helpers to create contexts of arbitrary values, i.e.
|
Package arbitrary contains helpers to create contexts of arbitrary values, i.e. |
Package commands contains helpers to create stateful tests based on commands.
|
Package commands contains helpers to create stateful tests based on commands. |
Package convey contains special assertion that come handy when using groper properties with goconvey.
|
Package convey contains special assertion that come handy when using groper properties with goconvey. |
Package gen contains all commonly used generators and shrinkers.
|
Package gen contains all commonly used generators and shrinkers. |
Package prop contains the most common implementations of a gopter.Prop.
|
Package prop contains the most common implementations of a gopter.Prop. |