You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm trying to use gopter to test a simple stateful object. The object is initialized with no existing state, and then methods are called. After each method is called, I'd like to execute a check on the internal state of the object. Note this means I don't want to maintain a separate State object, I'd basically like my SystemUnderTest to also act as the State object and I don't want to have to do any kind of updates in NextState. Ideally the Run method will be called, executing one of the object's methods, and then PostCondition will check some property of the object.
I believe I managed to get this working, but a few things that aren't clear:
Why does InitialStateGen run so many times? I would expect it to run once for each set of commands being executed but it seems to run much more than that.
Is it wrong to try and use the commands.SystemUnderTest as the commands.State? If I try to do so, it doesn't seem to work, since the commands.State and the commands.SystemUnderTests objects seem to come from different calls to InitialStateGen, so the commands.State doesn't see the changes effected to the commands.SystemUnderTest during calls to Run. I can work around this by returning the SystemUnderState as the result in Run and then checking the result in PostCondition while just ignoring the State. Is that the right thing to do? Related Stateful testing: Compare SystemUnderTest to State? #25
I've included a minimum viable example below.
Thanks!
package keeper
import (
"fmt""testing""github.com/leanovate/gopter""github.com/leanovate/gopter/commands""github.com/leanovate/gopter/gen"
)
typesysstruct {
heightintheightsmap[int]uint8
}
// store i under the latest height value and incremenet the height valuefunc (s*sys) New(iuint8) {
h:=s.heights.height+=1// bug when height is 5ifs.height==5 {
return
}
s.heights[h] =i
}
typenewCommanduint8func (valuenewCommand) Run(q commands.SystemUnderTest) commands.Result {
s:=q.(*sys)
s.New(uint8(value))
returns
}
// expect there to be an entry in the `sys.heights` map for each height up to the `sys.height`func (newCommand) PostCondition(state commands.State, result commands.Result) *gopter.PropResult {
// XXX: if I try to use the state instead of the result here, it doesn't work// (state doesn't seem to see the effects from Run)s:=result.(*sys)
fori:=0; i<s.height; i++ {
_, ok:=s.heights[i]
if!ok {
return&gopter.PropResult{Status: gopter.PropFalse}
}
}
return&gopter.PropResult{Status: gopter.PropTrue}
}
func (valuenewCommand) NextState(state commands.State) commands.State {
s:=state.(*sys)
returns
}
func (newCommand) PreCondition(state commands.State) bool {
returntrue
}
func (valuenewCommand) String() string {
returnfmt.Sprintf("New(%d)", value)
}
vargenNewCommand=gen.UInt8().Map(func(valueuint8) commands.Command {
returnnewCommand(value)
})
funccbCommands(t*testing.T) *commands.ProtoCommands {
return&commands.ProtoCommands{
NewSystemUnderTestFunc: func(initState commands.State) commands.SystemUnderTest {
returninitState
},
InitialStateGen: func(p*gopter.GenParameters) *gopter.GenResult {
// XXX: this function seems to execute many more times than Runresult:=&sys{
height: 0,
heights: make(map[int]uint8),
}
returngopter.NewGenResult(result, gopter.NoShrinker)
},
GenCommandFunc: func(state commands.State) gopter.Gen {
returngen.OneGenOf(genNewCommand)
},
}
}
funcTestSys(t*testing.T) {
parameters:=gopter.DefaultTestParametersWithSeed(1235)
properties:=gopter.NewProperties(parameters)
properties.Property("circular buffer", commands.Prop(cbCommands(t)))
properties.TestingRun(t)
}
Hello - thanks for a great testing library!
I'm trying to use gopter to test a simple stateful object. The object is initialized with no existing state, and then methods are called. After each method is called, I'd like to execute a check on the internal state of the object. Note this means I don't want to maintain a separate State object, I'd basically like my SystemUnderTest to also act as the State object and I don't want to have to do any kind of updates in NextState. Ideally the Run method will be called, executing one of the object's methods, and then PostCondition will check some property of the object.
I believe I managed to get this working, but a few things that aren't clear:
I've included a minimum viable example below.
Thanks!