espec 0.3.5

BDD test framework for Elixir inspired by RSpec.

Platform: Hex

Language: Elixir

License: MIT

Repository: https://github.com/antonmi/espec

View on registry: https://hex.pm/packages/espec/

Documentation: http://hexdocs.pm/espec/0.3.5


ESpec Build Status

ESpec is a BDD test framework for Elixir.

It is NOT a wrapper around ExUnit but the independent test framework written from scratch.

It is inspired by RSpec and the main idea is to be close to the RSpec DSL.

Features

  • Test organization with describe, context, it, and etc blocks
  • Familiar matchers: eq, be_close_to, raise_exception, etc
  • RSpec expectation syntax:
    • With expect helper: expect(smth1).to eq(smth2) or is_expected.to eq(smth) when subject is defined;
    • With old-style should: smth1 |> should eq smth2 or should eq smth when subject is defined.
  • before and finally blocks (like RSpec before and after)
  • let, let! and subject
  • Mocks with Meck

Contents

Installation

Add espec to dependencies in the mix.exs file:

def deps do
 ...
 {:espec, "~> 0.2.0", only: :test}
 ...
end
mix deps.get

Then run:

mix espec.init

The task creates spec/spec_helper.exs and spec/example_spec.exs.

Set preferred_cli_env for espec in the mix.exs file:

def project do
 ...
 preferred_cli_env: [espec: :test]
 ...
end

Or run with MIX_ENV=test.

Place your _spec.exs files into spec folder. use ESpec in the 'spec module'.

defmodule SomeSpec do
 use ESpec
 it do: expect(1+1).to eq(2)
 it do: (1..3) |> should have 2
end

Run specs

mix espec

Run specific spec:

mix espec spec/some_spec.exs:25

Context blocks

There are three macros with the same functionality: context, describe, and example_group.

Context can have description and options.

defmodule SomeSpec do
 use ESpec
 example_group do
 context "Some context" do
 it do: expect("abc").to match(~r/b/)
 end
 describe "Some another context with opts", focus: true do
 it do: 5 |> should be_between(4,6)
 end
 end
end

Available options are:

  • skip: true or skip: "Reason" - skips examples in the context;
  • focus: true - sets focus to run with --focus option.

There are also xcontext, xdescribe, xexample_group macros to skip example groups. And fcontext, fdescribe, fexample_group for focused groups.

Examples

example, it, and specify macros define the 'spec example'.

defmodule SomeSpec do
 example do: expect([1,2,3]).to have_max(3)
 it "Test with description" do
 4.2 |> should be_close_to(4, 0.5)
 end
 specify "Test with options", [pending: true], do: "pending"
end

You can use skip, pending or focus options to control evaluation. There are also macros:

  • xit, xexample, xspecify - to skip;
  • fit, fexample, fspecify, focus - to focus;
  • pending/1, example/1, it/1, specify/1 - for pending examples.
defmodule SomeSpec do
 use ESpec
 xit "skip", do: "skipped"
 focus "Focused", do: "Focused example"
 it "pending example"
 pending "it is also pending example"
end

before and finally

before blocks are evaluated before the example and finally runs after the example.

The blocks can return {:ok, key: value, ...}, so the keyword list will be saved in the ditionary and can be accessed in other before blocks, in the example, and in finaly blocks through 'double-undescore' __:

defmodule SomeSpec do
 use ESpec
 before do: {:ok, a: 1}
 context "Context" do
 before do: {:ok, b: __[:a] + 1}
 finally do: "#{__[:b]} == 2"
 it do: __.a |> should eq 1
 it do: __.b |> should eq 2
 finally do: "This finally will not be run. Define 'finally' before the example"
 end
end 

Note, that finally blocks must be defined before the example.

'double-underscore'

__ is used to share data between spec blocks. You can access data by __.some_key or __[:some_key]. __.some_key will raise exception if the key 'some_key' does not exist, while __[:some_key] will return nil.

The __ variable appears in your before, finally, let and example blocks.

before and finally blocks modify the dictionay when return {:ok, key: value}.

let, let!, and subject

let and let! have the same behaviour as in RSpec. Both defines memoizable functions in 'spec module'. let evaluates when accessing the function while let! called in 'before' chain. The __ is available in 'lets' but neither let nor let! can modify the dictionary.

defmodule SomeSpec do
 use ESpec
 before do: {:ok, a: 1}
 let! :a, do: __.a
 let :b, do: __.a + 1
 it do: expect(a).to eq(1)
 it do: expect(b).to eq(2)
end 

subject is just an alias for let(:subject). You can use is_expected macro when `subject is defined.

defmodule SomeSpec do
 use ESpec
 subject(1+1)
 it do: is_expected.to eq(2)
 it do: should eq 2
 context "with block" do
 subject do: 2+2
 it do: is_expected.to_not eq(2)
 it do: should_not eq 2
 end
end 

Matchers

Equality

expect(actual).to eq(expected) # passes if actual == expected
expect(actual).to eql(expected) # passes if actual === expected

Comparisons

Can be used with :>, :<, :>=, :<=, and etc.

expect(actual).to be operator, value 

Passes if apply(Kernel, operator, [actual, value]) == true

Regular expressions

expect(actual).to match(~r/expression/)
expect(actual).to match("string")

Enumerable

There are many helpers to test enumerable collections:

expect(collection).to be_empty #Enum.count(collection) == 0
... have(value) #Enum.member?(collection, value)
... have_all(fun) #Enum.all?(collection, func)
... have_any(fun) #Enum.any?(collection, func)
... have_at(position, value) #Enum.at?(collection, position) == value
... have_count(value) #Enum.count(collection) == value
... have_count_by(fun, value) #Enum.count(collection, func) == value
... have_max(value) #Enum.max(collection) == value
... have_max_by(fun, value) #Enum.max_by(collection, fun) == value
... have_min(value) #Enum.min(collection) == value
... have_min_by(fun, value) #Enum.min_by(collection, fun) == value

List specific

expect(list).to have_first(value) #List.first(list) == value
... have_last(value) #List.last(list) == value
... have_hd #hd(list) == value
... have_tl #tl(list) == value

Type checking

expect(:espec).to be_atom #is_atom(:espec) == true
... be_binary
... be_bitstring
... be_boolean
... ...
... ...
... should be_tuple
... be_function
... be_function(arity)

Exceptions

expect(function).to raise_exception
expect(function).to raise_exception(ErrorModule)
expect(function).to raise_exception(ErrorModule, "message")

Throws

expect(function).to throw_term
expect(function).to throw_term(term)

Change state

Test if call of function1 change the function2 returned value to smth or from to smth

expect(function1).to change(function2, to)
expect(function1).to change(function2, from, to) 

Mocks

ESpec uses Meck to mock functions. You can mock the module with 'allow accept':

defmodule SomeSpec do
 use ESpec
 before do: allow(SomeModule).to accept(:func, fn(a,b) -> a+b end)
 it do: expect(SomeModule.func(1, 2)).to eq(3)
end

Note, when you mock some function in module, meck creates an absolutely new module.

You can also pass a list of atom-function pairs to the accept function:

allow(SomeModule).to accept(f1: fn -> :f1 end, f2: fn -> :f2 end)

There is also an expectation to check if the module accepted a function call:

defmodule SomeSpec do
 use ESpec
 before do: allow(SomeModule).to accept(:func, fn(a,b) -> a+b end)
 before do: SomeModule.func(1, 2)
 it do: expect(SomeModule).to accepted(:func, [1,2])
end

expect(SomeModule).to accepted(:func, [1,2]) just checks meck.history(SomeModule).

Configuration

TODO

веселые картинки развлекательные гифки интресные факты смешные видео смешные истории из соцсетей

Dependencies


GitHub Repository

antonmi/espec antonmi/espec

Behaviour Driven Development for Elixir

Language: Elixir

Created: March 17, 2015 16:06

Last updated: April 01, 2015 05:51

Last pushed: March 31, 2015 18:11

Size: 430 KB

Stars: 2

Forks: 0

Watchers: 1

Open issues: 4

Top Contributors

Anton Mishchuk

Releases

  • 0.3.5 - April 01, 2015 12:24
  • 0.3.0 - March 29, 2015 22:22
  • 0.2.0 - March 26, 2015 21:07
  • 0.1.0 - March 25, 2015 13:48

Related Projects

blacksmith 0.1.2
Elixir fake data generation for testing and development
Hex - Elixir - Apache-2.0 - Updated 8 days ago - 28 stars
cloudi_core 1.4.0
Erlang/Elixir Cloud Framework
Hex - Erlang - BSD-3-Clause - Updated 2 months ago - 2 stars
cloudi_service_db 1.4.0
Erlang/Elixir Cloud Framework Database (in-memory/testing/generic)
Hex - Erlang - BSD-3-Clause - Updated 2 months ago
excheck 0.2.1
Property-based testing library for Elixir (QuickCheck style).
Hex - Elixir - MIT - Updated 2 months ago - 37 stars
exvcr 0.4.0
HTTP request/response recording library for elixir, inspired by VCR.
Hex - Elixir - MIT - Updated about 2 months ago - 40 stars
веселые картинки развлекательные гифки интресные факты смешные видео смешные истории из соцсетей