fsprojects / TickSpec

Lean .NET BDD framework with powerful F# integration
Apache License 2.0
133 stars 23 forks source link

Events (BeforeStep, AfterStep, AfterScenario) can't access arguments #56

Closed stefan-schweiger closed 5 months ago

stefan-schweiger commented 1 year ago

Currently it's not possible to use shared arguments in Events like BeforeStep, AfterStep, AfterScenario (I don't think it makes sense for BeforeScenario)

For example this results in an error:

[<BeforeScenario>]
let setup () =
    { Server = TestServer.Start() }

[<AfterScenario>]
let teardown ctx =
    ctx.Server.Stop()
System.Reflection.TargetParameterCountException
Parameter count mismatch.
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at TickSpec.ScenarioRun.invoke(IInstanceProvider provider, MethodInfo m, Object[] ps)
   at TickSpec.ScenarioRun.invokeEvents@171-1.Invoke(MethodInfo mi)
   at Microsoft.FSharp.Collections.SeqModule.Iterate[T](FSharpFunc`2 action, IEnumerable`1 source) in D:\a\_work\1\s\src\fsharp\FSharp.Core\seq.fs:line 497
   at TickSpec.ScenarioRun.generate[a,b](IEnumerable`1 events_0, IEnumerable`1 events_1, IEnumerable`1 events_2, IEnumerable`1 events_3, IDictionary`2 parsers, a scenario, IEnumerable`1 lines, FSharpRef`1 serviceProviderFactory, Unit unitVar0)
   at <StartupCode$TickSpec>.$TickSpec.action@185.Invoke(Unit arg40@)
   at <StartupCode$TickSpec>.$TickSpec.GenerateScenarios@187-1.Invoke()

I know I can just use a mutable value instead, but then what's the point of using arguments at all? I think it would be great to be able to have the same arguments available in the events as in the step definitions.

mchaloupka commented 1 year ago

Hi,

sorry for the delay.

Tickspec does not implement integration with the unit testing framework to integrate with before steps and after steps. That is to keep it independent from the runner.

The right solution for your problem is to set a StepDefinitions.ServiceProviderFactory property. That is called before every scenario to get IServiceProvider. So, you can create instance of the server, start it and return a service provider that is able to return the server. That way, you can get the server as parameter in your steps. And at the end of a scenario execution it calls the Dispose() method if the service provider implements it.

See advanced features in the readme. Feel free to reopen if it is not clear or you run into any issues.

mchaloupka commented 1 year ago

Ah, actually I realized that I misread it. You mean the internal events that Tickspec provides. You are correct, that is a gap in functionality that should be filled in. In the meantime, you can use the above workaround.

OnurGumus commented 6 months ago

Any love for this issue is greatly appreciated. This is the final missing piece.