Giter VIP home page Giter VIP logo

tickspec's Introduction

Build Status NuGet Status Join the chat at https://gitter.im/fsprojects/TickSpec

Project Description

A lightweight Behaviour Driven Development (BDD) framework for .NET that'll fit how you want to test.

  1. Describe behaviour in plain text using the Gherkin business language, i.e. Given, When, Then.
  2. Easily execute the behaviour against matching F# 'ticked' methods, or attribute-tagged C# or F# methods.
  3. Run via your normal test runners or plugins (xUnit, NUnit or standalone)
  4. Set breakpoints in the scenarios, step definitions or your code and go (setting breakpoints in the Gherkin is currently not supported in .NET Standard version)

Example video: http://www.youtube.com/watch?v=UuTL3nj9fIE

Installation

Simply reference TickSpec via NuGet or Paket, download the assembly or build the project from source.

Feature specification (Plain text)

Feature: Refunded or replaced items should be returned to stock

Scenario: Refunded items should be returned to stock
    Given a customer buys a black jumper
    And I have 3 black jumpers left in stock
    When he returns the jumper for a refund
    Then I should have 4 black jumpers in stock

Step definitions (F#)

type StockItem = { Count : int }

let mutable stockItem = { Count = 0 }

let [<Given>] ``a customer buys a black jumper`` () = ()

let [<Given>] ``I have (.*) black jumpers left in stock`` (n:int) =
    stockItem <- { stockItem with Count = n }

let [<When>] ``he returns the jumper for a refund`` () =
    stockItem <- { stockItem with Count = stockItem.Count + 1 }

let [<Then>] ``I should have (.*) black jumpers in stock`` (n:int) =
    let passed = (stockItem.Count = n)
    Debug.Assert(passed)

Step definitions (F# without mutable field)

type StockItem = { Count : int }

let [<Given>] ``a customer buys a black jumper`` () = ()
      
let [<Given>] ``I have (.*) black jumpers left in stock`` (n:int) =
    { Count = n }
      
let [<When>] ``he returns the jumper for a refund`` (stockItem:StockItem) =
    { stockItem with Count = stockItem.Count + 1 }
      
let [<Then>] ``I should have (.*) black jumpers in stock`` (n:int) (stockItem:StockItem) =
    let passed = (stockItem.Count = n)
    Debug.Assert(passed)

Step definitions (C#)

public class StockStepDefinitions
{
   private StockItem _stockItem;

   [Given(@"a customer buys a black jumper")]
   public void GivenACustomerBuysABlackJumper()
   {
   }

   [Given(@"I have (.*) black jumpers left in stock")]
   public void GivenIHaveNBlackJumpersLeftInStock(int n)
   {
      _stockItem = new StockItem() { Count = n };
   }

   [When(@"he returns the jumper for a refund")]
   public void WhenHeReturnsTheJumperForARefund()
   {
      _stockItem.Count += 1;
   }

   [Then(@"I should have (.*) black jumpers in stock")]
   public void ThenIShouldHaveNBlackJumpersInStock(int n)
   {
      Debug.Assert(_stockItem.Count == n);
   }
}

Type Conversions

Arguments to Step Methods will be converted from string to the declared types of the Step Method parameters when possible. The following conversions are supported:

  • Enum types
  • Union types with no parameters
  • Nullable<T> types where the inner T type can be converted from string
  • Tuple types where each element can be converted from string
  • Array types T [] where T can be converted from string and the original string is comma delimited
  • Types supported by System.Convert.ChangeType

Tables

A table may be passed as an argument to a Step Method:

When a market place has outright orders:
   | Contract | Bid Qty | Bid Price | Offer Price | Offer Qty |
   | V1       | 1       | 9505      |             |           |
   | V2       |         |           | 9503        | 1         |

The parameter can be declared with type Table:

let [<When>] ``a market place has outright orders:`` (table:Table) =
    outrightOrders <- toOrders table

Alternatively, the parameter can be converted to an array of records, or other type with constructor parameters supported by the Type Conversions

type OrderRow = { Contract: string; BidQty: string; BidPrice: string; OfferPrice: string; OfferQty: string }

let [<When>] ``a market place has outright orders:`` (orderRows: OrderRow[]) =
    outrightOrders <- toOrders orderRows

The Table parameter must appear after any regex capture parameters, and before any Functional Injection parameters:

let [<Given>] ``A market place``() =
    createMarketPlace()

let [<When>] ``a market place has outright (.*) orders:``
    (orderType: string)       # captured
    (table: Table)            # table
    (maketPlace: MarketPlace) # injected
    =
  ...

Lists

A bullet list may be passed to a Step Method similarly to a Table:

Scenario: Who is the one?
Given the following actors:
    * Keanu Reeves
    * Bruce Willis
    * Johnny Depp
When the following are not available:
    * Johnny Depp
    * Bruce Willis
Then Keanu Reeves is the obvious choice

The parameter type must be an array type supported by the Type Conversions:

let [<Given>] ``the following actors:`` (actors : string[]) =
    availableActors <- Set.ofArray actors

Advanced features

Resolving referenced types (beta)

As shown in Step definitions (F# without mutable field), TickSpec also allows one to request additional parameters along with the captures from the regex holes in the step name as per typical Gherkin based frameworks. Such additional parameters can be fulfilled via the following mechanisms:

  • Instances returned from Step Method return values: This involves generating and stashing an instance in one of the preceding steps in the scenario. Typically this is achieved by returning the instance from the Step Method. Whenever a step has a return value, the the value is saved under it's type (the return type of the Step Method controls what the type is). Multiple values can be returned from a Step Method by returning a tuple. There can be only one value per type stashed per scenario run. When a parameter is being resolved, TickSpec first attempts to resolve from this type-to-instance caching Dictionary.

  • Resolving dependencies: If an instance cannot be located in the type-to-instance cache based on a preceding step having stashed the value, TickSpec will attempt to use the 'widest' constructor (the one with the most arguments) of the required type to instantiate it. Any input arguments to the constructor are all resolved recursively using the same mechanism. Any constructed instances are also cached in the type-to-instance cache, so next time it will return the same instance.

  • Accessing scenario metadata: You can access contextual information about the scenario within which a step definition is executing (e.g. tags). To do this, add a parameter of type ScenarioMetadata in the step definition argument list (or in a constructor parameter list of a dependency) scenario information (e.g. tags), then you can reference ScenarioMetadata in your method argument (or in constructor of dependencies) and you will get an instance describing the scenario which is invoked.

The lifetime of instances is per-scenario:- Each scenario run starts an empty type-to-instance cache, and at the end of the scenario the cache gets cleared. Moreover, if any instance is IDisposable, Dispose will be called.

See the example projects DependencyInjection and FunctionalInjection for typical and advanced examples of using this mechanism.

Custom type resolver (beta)

While the typical recommended usage of TickSpec is to keep the step definitions simple and drive a system from the outside in the simplest fashion possible, in some advanced cases it may be useful to provide a custom type resolver. This can be achieved by setting the StepDefinitions.ServiceProviderFactory property. This factory method is used once per scenario run to establish an independent resolution context per scenario run. The IServiceProvider instance is used to replace the built in instance construction mechanism (see Resolving dependencies in the previous section: Resolving referenced types). If the IServiceProvider implementation yielded by the factory also implements IDisposable, Dispose is called on the Service Provider context at the end of the scenario run.

See the CustomContainer example project for usage examples - the example demonstrates wiring of Autofac including usage of lifetime scopes per scenario and usage of the xUnit 2+ Shared Fixtures to correctly manage the sharing/ifetime of the container where one runs xUnit Test Classes in parallel as part of a large test suite.

Contributing

Contributions are welcome, particularly examples and documentation. If you'd like to chat about TickSpec, please use the the gitter channel.

For issues or suggestions please raise an Issue. If you are looking to extend or change the core implementation, it's best to drop a quick note and/or a placeholder PR in order to make sure there is broad agreement on the scope of the change / nature of the feature in question before investing significant time on it; we want to keep TickSpec powerful, but minimal.

tickspec's People

Contributors

bartelink avatar dantup avatar deyanp avatar mbuhot avatar mchaloupka avatar michalkovy avatar ptrelford avatar sergey-tihon avatar xoltar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tickspec's Issues

Documentation missing step for setup

After installing the Nuget package, pressing 'F5' video doesn't run the tests as suggested in the documentation video (you can't run a class library). There must be some step not mentioned in the documentation needed to complete setup of TickSpec.

Steps to Replicate:

  1. Create an F# xUnit test project in Visual Studio 2019
  2. Add Feature.txt and StepDefinitions.fs files
  3. Install TickSpec.xUnit
  4. Press F5

Result: Error message box saying "A project with an Output Type of Class Library cannot be started directly [...]"

TickSpec seems to work a bit different from SpecFlow. What is the best way to run a TickSpec test from Visual Studio?

Generating test cases at build time

Hi,

i like the lean approach of TickSpec but i found that generating test cases at runtime as described here has quite some drawbacks as described in detail in this article and this article so i have prototyped "test case generation at build time" and successfully use it in one of my F# projects.

The code can be found here: https://github.com/plainionist/TickSpec.Build

I just wanted to share this with you and your community and ask whether you find this approach interesting and would consider integrating it into TickSpec (which would certainly require some improvements like C# support and support for other test frameworks like XUnit)

Incorrect Given/When/Then behavior (according to Gherkin Reference)

I believe, according to the behavior I am seeing in some of my tests, and in the source code, that step definitions are implemented in a way that is different than the Gherkin definition.

https://docs.cucumber.io/gherkin/reference/#steps

According to the definition the key word (Given, When, or Then) should not be taken into account when initially loading a step definition. However, you should not be allowed to use Given and Then on the same step definition within the same scenario.

I have the case where I've defined a When step definition using the When Attribute, but I am invoking that step definition underneath a Give (using And however). When running with Xunit, I am told that I am missing a step definition.

My setup looks something like the following, for clarity:

Step definition

let [<When>] ``I have defined a step definition`` () = () 
Feature: Test Feature

  Scenario: All initial keywords are fair game 
    Given I am writing a test
      And I have defined a step definition
    When I call it with a different keyword initially
    Then the step definition should succeed

Please let me know if this is not intended functionality, or if it is functioning as intended. This was just unexpected behavior compared to my previous BDD experience.

Support for dotnet core 2.0

Do you have any plans to add support for dotnet core 2.0?
Notw it fails because It can't load the features by reflection.

Newlines are removed from doc strings

It seems Tickspec is filtering out all empty lines in a doc string, e.g.

...
Then the generated file has the following content
"""
line1

line3

line5

"""

The resulting argument passed to the Then step looks like

line1
line3
line5

Can you pls confirm this is a bug in TickSpec (Gherkin seems to preserve newlines in doc strings) ?

Support for Rules

I saw recent versions of Gherkin support the Rule thing along with the ability to add tags. It would be great if tickspec can support this.

The nuget is outdated

The nuget indicate a version from 2014 and some features like "functional style without mutable" doesn't work with error message :
"Step methods must return void/unit on line 5 in Feature: Refunded or replaced items should be returned to stock
"And I have 3 black jumpers left in stock"

Note that this sample works well on the sample part.

I guess that the nuget hasn't be pushed.

Could you push the new version ?

Thanks!

How to get to the tags from within a step implementation function (Xunit)?

Imagine I have some tag on a scenario-level:

Feature: Xxx
  @mocked
  Scenario: YYY
    Given some given
    When some when
    Then some then

How can I get to the tags collection from within a step like:

let [<Given>] ``some given``  () =
  // how to the scenario tags collection here?
  failwith "TODO"

I have implemented (similar to what I explained in #46) a static dictionary in which (based on ManagedThreadId) I inject the tags in the Theory/MemberData decorated stub function, and get them later on from the step implementation, however I am sure @mchaloupka will have a better idea ...

I also looked at https://github.com/fsprojects/TickSpec/tree/master/Examples/ByFeature/TaggedExamples but could not understand it ..

Functional injection with BeforeScenario attribute throws System.InvalidProgramException in .NET Framework project

I'm working on .NET Framework test project with TickSpec and NUnit.
When using BeforeScenario attribute with functional injection coding style I am getting System.InvalidProgramException.

Steps to reproduce on TickSpec solution:

  1. Change target of Examples.ByFeature.FunctionalInjection project to .NET Framework 4.7.2 only
  2. Change file StockSteps.fs to:
module StockStepDefinitions

open NUnit.Framework
open Retail
open TickSpec

let [<BeforeScenario>] BeforeScenario () =
  { Count = -1 }

let [<Given>] ``a customer buys a black jumper`` () = ()

let [<Given>] ``I have (.*) black jumpers left in stock`` (n:int) (stockItem:StockItem) =  
    { stockItem with Count = n }

let [<When>] ``he returns the jumper for a refund`` (stockItem:StockItem) =  
    { stockItem with Count = stockItem.Count + 1 }

let [<Then>] ``I should have (.*) black jumpers in stock`` (n:int) (stockItem:StockItem) =     
    let passed = (stockItem.Count = n)
    Assert.True(passed)
  1. Run tests for project

You should get test result like below:

[0-1001]NUnit.TickSpec+FeatureFixture.Scenario 1: Refunded items should be returned to stock

System.InvalidProgramException : Common Language Runtime detected an invalid program.
   at Scenario 1: Refunded items should be returned to stock.Run()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at NUnit.TickSpec.FeatureFixture.Bdd(Scenario scenario) in C:\sources\TickSpec\Examples\ByFeature\FunctionalInjection\NunitWiring.fs:line 21

The issue is definitely with code generation for .NET Framework runtime.
The interesting thing is when I reverted commit 7ed773a (Enable .NET Framework features again) then everything worked properly even when test project was targeting .NET 4.7.2.
Maybe this code generation is needed only for .NET Framework 4.5 exclusively?

Takes only the second value of a tuple

I have following case which did not work as I expected.

module CalculatorStepDefinition

open NUnit.Framework
open TickSpec

let [<Given>] ``I have two numbers`` () =
    3, 5

let [<When>] ``They are added together`` numbers =
    Calculator.add (fst numbers) (snd numbers)

let [<Then>] ``the result is calculated correctly`` (result:int) =
    Assert.AreEqual(3 + 5, result)

module Calculator

let add a b = a + b

The result is 10 and when I debugged I really see that numbers tuple contains 5 and 5.

Expected behavior is to take the tuple and pass it on as tuple with correct values.

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

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 [email protected](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>[email protected](Unit arg40@)
   at <StartupCode$TickSpec>[email protected]()

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.

"Missing step definition" when applying multiple step attributes to single step

Hi. In the comments for issue #25, @michalkovy notes that it is possible to allow a single step to function both as (say) a Given and When step.

We could potentially have such attribute but you can do the same today by writing:

let [<Given; When; Then>] ``I have defined a step definition`` () = ()1

However, this is not working for me today in 2.0.2.

This is what I have:

let [<Given; When>] ``user launches site`` (page: IPage) (uri: Uri) = 
    page.GotoAsync(uri.ToString()) |> Async.AwaitTask |> Async.RunSynchronously
Scenario: Root loads OK
    When user launches site
    Then page loaded ok

Scenario: Home page loads OK via navbar
    Given user launches site
    When clicking Home on navbar
    Then page title reads "Home"

This is what TickSpec has to say:

    TickSpec.StepException : Missing step definition on line 4 in Site is alive and healthy
	"When user launches site"

Note that the Given step still works fine.

I can work around it by duplicating the step, but yuck.

This workaround does work:

let [<When>] ``DUPLICATE user launches site`` (page: IPage) (uri: Uri) = 
    ``user launches site`` page uri
Scenario: Root loads OK
    When DUPLICATE user launches site
    Then page loaded ok

Possible improvement on Interactive implementation

the interactive implementation is way different than the other one, isn't there a way to make a consistent way of declaring the steps and just then invoke something like TickSpec.RunInteractive ?

#r "nuget: TickSpec"
//#load "FeatureRunner.fs" <-- avoiding this as all implementation is different, and cannot reuse attributes



open TickSpec
open System.Diagnostics
open System.Reflection
open System.IO
open Swensen.Unquote


type StockItem = { Count : int }

type MyFeature() =

    [<Given>]
    member _. ``a customer buys a black jumper`` () = ()
      
    [<Given>]
    member _. ``I have (.*) black jumpers left in stock`` (n:int) =
        { Count = n }
      
    [<When>]
    member _.``he returns the jumper for a refund`` (stockItem:StockItem) =
        { stockItem with Count = stockItem.Count + 1 }
      
    [<Then>]
    member _.``I should have (.*) black jumpers in stock`` (n:int) (stockItem:StockItem) =
        let passed = (stockItem.Count = n)
        Debug.Assert(passed)



let declaredTypes = [| typeof<MyFeature> |]

let definitions = new StepDefinitions(types = declaredTypes)

let feature1 = __SOURCE_DIRECTORY__ + "/Scenario.feature"

let feature = definitions.GenerateFeature feature1

let scenario = feature.Scenarios |> Seq.head

scenario.Action.Invoke()

Just a suggestion, from the documentation it seems very complicated and much different.
I think this could provide benefits e.g. comparing with python behave:
https://behave.readthedocs.io/en/latest/

Something like the above doesnt seem to work, as parsing is not effecting, might be issues with reflection, though we have a declared type in FSI, probably that part is not working as expected...

val scenario : Scenario =
  { Name = "Scenario: Refunded items should be returned to stock"
    Description =
                 "    Given a customer buys a black jumper
    And I have 2 bl"+[119 chars]
    Action = TickSpec.Action
    Parameters = [||]
    Tags = [||] }
val it : unit = ()

Could not load file or assembly 'FSharp.Core, Version=4.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'

I'm trying to setup a project and I have the follow error :

    Features.Addition [FAIL]
      System.TypeInitializationException : The type initializer for '<StartupCode$tickspecbdd>.$Features' threw an exception.
      ---- System.IO.FileNotFoundException : Could not load file or assembly 'FSharp.Core, Version=4.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
      Stack Trace:
           at Features.get_source()
           at Features.scenarios(String resourceName)
        ----- Inner Stack Trace -----
           at TickSpec.StepDefinitions..ctor(Type[] types)
           at Features.AssemblyStepDefinitionsSource..ctor(Assembly assembly)
           at <StartupCode$tickspecbdd>.$Features..cctor()
  Finished:    tickspecbdd

This is my code

module Features

open TickSpec
open Xunit

/// Represents a set of Step Definitions available within a given Assembly
type AssemblyStepDefinitionsSource(assembly : System.Reflection.Assembly) =
    let definitions = StepDefinitions(assembly)    
    /// Yields Scenarios generated by parsing the supplied Resource Name and binding the steps to their Step Definitions
    member __.ScenariosFromEmbeddedResource resourceName : Scenario seq =
        let stream = assembly.GetManifestResourceStream(resourceName)
        definitions.GenerateScenarios(resourceName, stream)

/// Adapts a Scenario Sequence to match the required format for an xUnit MemberData attribute
module MemberData =
    let ofScenarios xs = xs |> Seq.map (fun x -> [| x |])
let x =     System.Reflection.Assembly.GetExecutingAssembly()
System.Console.WriteLine(x)
let source = AssemblyStepDefinitionsSource(x)
System.Console.WriteLine(source)
let scenarios resourceName = source.ScenariosFromEmbeddedResource resourceName |> MemberData.ofScenarios

[<Theory; MemberData("scenarios", "Refunded.feature")>]
let Addition (scenario : Scenario) = scenario.Action.Invoke()

Any ideas?

Big scenarios execution time

Hi,

It takes ~111 ms to run all the 3 scenarios from the ByFramework/xUnit example when I run it as a standalone project:

image

But when I move that example to one of my test projects with 600+ other tests, the execution time raises to 5+ seconds, and each scenario is executed for more than a second:

image

Is there a way to reduce scenario execution time in the second case?

Thanks

VS Code/.NET Test Explorer and "dotnet test -t" do not list the individual scenarios

I am surprised that VS Code's .NET Test Explorer (which uses "dotnet test -t" command) does not display the individual scenarios in the treeview, but only the features.

This means I cannot run/debug individual scenarios in a feature, I have to always run/debug all of them. Imagine 13 scenarios in a feature, and I want to troubleshoot only the last one ..

Is this by design (impossible to list scenarios due to the xUnit wiring)?

P.S: We are trying to use TickSpec with xUnit ...

Expecto example

Is there any interest in examples of using TickSpec with Expecto?

I created a proof of concept to learn the framework.

I can expand it to be in line with the other examples in this repo and send a PR.

Replace placeholders in table from examples?

Any way to replace automatically placeholders inside a table from the examples?

E.g.

Feature: Xxxx

  Scenario Outline: YYY
    Given xxx
    When yyy <Placeholder1>
    | Key | Value |
    | SomeKey | <Placeholder2> |
    Then  zzzz

  Examples:
   | Placeholder1 | Placeholder2 |
   | Value1 | Value2 |
   | Value3 | Value4 |

Ideally I would also not need to put Placeholder1 in the step definition for the scenario outline to instantiate 2 scenarios ...

I am currently doing it like this as a workaround:

module Scenario =
    let scenarios = Dictionary<string,Scenario> ()

    let setCurrent scenario =
        scenarios.[Thread.CurrentThread.ManagedThreadId.ToString()] <- scenario
    let getCurrent () =
        let found, foundScenario = scenarios.TryGetValue(Thread.CurrentThread.ManagedThreadId.ToString())
        if found then Some foundScenario else None
    let getCurrentParameters () =
        getCurrent ()
        |> Option.map (fun foundScenario ->
            foundScenario.Parameters
            |> Map.ofArray )
        |> Option.defaultValue Map.empty

...

    [<Theory; MemberData("scenarios", "Xxxx.feature")>]
    member this.Xxxxx (scenario : Scenario) = 
        Scenario.setCurrent scenario
        scenario.Action.Invoke()

... 
let [<When>] ``yyy (.*)``
    (placeholder1: string)
    (properties: Table)
    (ctx:Context)
    =
   let parameters = Scenario.getCurrentParameters() 
  // here manually replace the values in properties Table ...

Any better/more elegant and automated ways?

Support for dependency injection

Usage of dependency injection to create instances will help to resolve more complicated dependencies. Moreover, it enables proper usage of IDisposable classes.

@michalkovy has already a working version using BoDi (DI used in SpecFlow). It would be nice to get it into the official tickspec nuget release. If you will agree, we can create pull request with the feature.

Override gherkin keywords

As I see the code, for now we have ability to use english language only to use standard gherkin keywords: Feature, Scenario, Given, When, Then

Seems like it will be good feature if end users will be able to override these keywords, for example, if we need to create gherkin tests on the other language.

Show line number of failed step

For bigger scenarios (having multiple THEN steps) it would be helpful to see the line number of the step where the step is defined in the feature file.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.