Skip to content
forked from anyalir/behave

Behaviour driven development for ExUnit with product management friendly readable scenarios.

License

Notifications You must be signed in to change notification settings

ClarkSource/behave

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Behave

Behaviour driven development for ExUnit with product management friendly readable scenarios.

Behave, baby, behave!

Features

  • Minimal DSL on top of ExUnit.
  • given, act, check instead of given, when, then to avoid naming collisions.
  • Api can be used without macros, if necessary
  • Steps are just functions, scenarios are just ExUnit tests.
  • Not a full gherkin implementation, it just gives you the ability to decompose tests into reusable named steps.
  • Separate DSLs for defining scenarios and implementing test steps.
  • Dependency Free. Use whatever assertion, mocking and testing libraries you want.

Usage

Assuming you have a BDD stlye scenario like this:

Scenario make coffee
  Given a coffee machine
  And it has 250 ml of water in its tank
  And it has java coffee beans in its reservoir
  When i press the "make coffee" button
  Then it makes coffee

In your ExUnit test, use the Behave module:

defmodule MyCoffeeMachineTest do
  use ExUnit.Case
  use Behave, steps: [MyCoffeeMachineTestSteps]

  ...
end

Notice we're passing :steps to Behave, this is the module where you define your test steps.

Then, use the Behave DSL to implement your scenario:

defmodule MyCoffeeMachineTest do
  use ExUnit.Case
  use Behave, steps: [MyCoffeeMachineTestSteps]

  scenario "make coffee with dsl" do
    given "coffee machine"
    given "it has water", amount: 250
    given "it has coffee", cultivar: :java
    act "i press the button"
    check "it makes coffee"
  end
end

Your TestSteps modules should be defined in a directory that gets picked up by the compiler, such as test/support. In those modules, you need to define a step function for each test step (given, act, check).

defmodule TestSteps do
    use Behave.Scenario # for access to the step definition DSL
    import ExUnit.Assertions

    given "coffee machine" do
      {:coffee_machine, CoffeeMachine.new()}
    end

    ...
end

The given macro expects you to return a tuple of an atom that will be used to refer to the returned value, and the value that should be available to subsequent steps. You can run arbitrary code before returning the tuple. If you do not need the given steps to produce any values, return :ignore instead. This is useful if you want to execute a given just for it's side effects. Note that you cannot just return :nil.

given s can take arguments, too:

# in scenario:

    given "it has water", amount: 250
    
# in step definition:

    given "it has water", amount: amount do
      {:coffee_machine, &CoffeeMachine.add_water(&1, amount)}
    end

If you pass in a function as the second argument of the tuple, it will execute the function and pass in the value of the key, if it has been set by a prior step. The value will be overwritten with this function's return value, similar to how update_in works.

act works similarly, but the keys it returns will be separated from the keys that the given steps have prepared. act also has access to all values set in prior givens through an injected data map:

    act "i press the button" do
      {:coffee, CoffeeMachine.brew(data.coffee_machine)}
    end

Note that it is not possible to overwrite values set in givens. If you need to modify a value created by a given, use a given. act can accept arguments, just as given can.

Finally, run your assertions in a check step:

    check "it makes coffee" do
      assert results.coffee != :disappointment
    end

checks cannot store any values. Their return values are always discarded. However, they have access to both the data and results maps. data contains all the values set in given steps, and results contains the values from the act steps. check can accept arguments as well.

All that said and done, just run your test like any ExUnit test 🎉

Installation

If available in Hex, the package can be installed by adding behave_bdd to your list of dependencies in mix.exs:

def deps do
  [
    {:behave_bdd, "~> 0.1.1"}
  ]
end

Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/behave_bdd.

About

Behaviour driven development for ExUnit with product management friendly readable scenarios.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Elixir 100.0%