• Stars
    star
    103
  • Rank 321,854 (Top 7 %)
  • Language
    Crystal
  • License
    MIT License
  • Created almost 9 years ago
  • Updated about 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Enhanced `spec` testing library for [Crystal](http://crystal-lang.org/).

spec2 Build Status

Enhanced spec testing library for Crystal.

Example

Spec2.describe Greeting do
  subject { Greeting.new }

  describe "#greet" do
    context "when name is world" do
      let(name) { "world" }

      it "greets the world" do
        expect(subject.greet(name)).to eq("Hello, world")
      end
    end
  end
end

Installation

Add it to shard.yml

dependencies:
  spec2:
    github: waterlink/spec2.cr
    version: ~> 0.9

Goals

  • No global scope pollution
  • No Object pollution
  • Ability to run examples in random order
  • Ability to specify before and after blocks for example group
  • Ability to define let, let!, subject and subject! for example group

Roadmap

1.0

  • Configuration through CLI interface.
  • Filters.
  • Shared examples and example groups.

Usage

require "spec2"

Top-level describe

Spec2.describe MySuperLibrary do
  describe Greeting do
    # .. example groups and examples here ..
  end
end

If you have test suite written for Spec and you don't want to prefix each top-level describe with Spec2., you can just include Spec::GlobalDSL globally:

include Spec2::GlobalDSL

# and then:
describe Greeting do
  # ...
end

Writing examples

Spec2.describe "some tests" do
  it "is a test name here" do
    # .. this is the example here ..
  end

  pending "is a pending test here" do
    # .. this example will not be executed ..
  end
end

Expect syntax

expect(greeting.for("john")).to eq("hello, john")

If you have big codebase that runs on Spec, you can use this to enable #should and #should_not on Object:

Spec2.enable_should_on_object

List of builtin matchers

  • eq("hello, world") - asserts actual is equal to expected
  • raise_error(ErrorClass [, message_matcher]) - checks if block raises expected error
  • be(42) - asserts actual is the same as expected
  • match(/hello .+/) - asserts actual is matching provided regexp
  • be_true - asserts actual is equal true
  • be_false - asserts actual is equal false
  • be_truthy - asserts actual is not nil or false
  • be_falsey - asserts actual is nil or false
  • be_nil - asserts actual is equal nil
  • be_close(42, 0.01) - asserts actual is in delta-proximity of expected
  • expect(42).to_be < 45 - asserts arbitrary method call on actual to be truthy
  • be_a(String) - asserts actual to be of expected type (uses is_a?)

Random order

Spec2.random_order

# this is what happens under the hood
Spec2.configure_order(Spec2::Orders::Random)

To configure your own custom order you can use:

Spec2.configure_order(MyOrder)

Class MyOrder should implement Order protocol and Order::Factory class protocol (see it here). See also a random order implementation.

No color mode

Spec2.nocolor

# this is what happens under the hood
Spec2.configure_output(Spec2::Outputs::Nocolor)

To configure your own custom output you can use:

Spec2.configure_output(MyOutput)

Class MyOutput should implement Output protocol and Output::Factory class protocol (see it here). See also a default colorful output implementation.

Documentation reporter

Spec2.doc

# this is what happens under the hood
Spec2.configure_reporter(Spec2::Reporters::Doc)

To configure your own custom reporter you can use:

Spec2.configure_reporter(MyReporter)

Class MyReporter should implement Reporter protocol and Reporter::Factory class protocol (see it here). See also a default reporter implementation.

If you are creating a custom reporter, you might want to use ElapsedTime class to report elapsed time for the test suite. Example usage:

output.puts "Finished in #{::Spec2::ElapsedTime.new.to_s}"

Configuring custom Runner

Spec2.configure_runner(MyRunner)

Class MyRunner should implement Runner protocol and Runner::Factory class protocol (see it here). See also a default runner implementation.

before

before - register a hook that is run before any example in current and all nested contexts.

before { .. do some stuff .. }

after

after - register a hook that is run after any successful example in current and all nested contexts.

after { .. do some stuff .. }

let

let(name) { value } - register a binding of certain value to name. Lazy: provided block will only be evaluated when needed in example and only once per example.

let(answer) { 42 }

it "is correct answer" do
  expect(answer).to eq(42)
end

let!

let(name) { value } - register a binding of certain value to name. It is not lazy: provided block will be evaluated before each example exactly once.

let!(answer) { 42 }

it "is correct answer" do
  expect(answer).to eq(42)
end

described_class

For describe ... blocks, that describe a class, there is a shortcut to reference that class:

describe Example do
  it "can be created" do
    expect(described_class.new.greet).to eq("hello world")
    # instead of `Example.new.greet`.
  end
end

subject

subject { value } - register a subject of your test with provided value. Lazy.

subject { Stuff.new }

it "works" do
  expect(subject.answer).to eq(42)
end

subject(name) { value } - registers a named subject of your test with provided value with provided name. Lazy.

subject(stuff) { Stuff.new }

it "works" do
  expect(stuff.answer).to eq(42)
end

subject!

subject! { value } - register a subject of your test with provided value. It is not lazy.

subject! { Stuff.new }

it "works" do
  expect(subject.answer).to eq(42)
end

subject!(name) { value } - registers a named subject of your test with provided value with provided name. It is not lazy.

subject!(stuff) { Stuff.new }

it "works" do
  expect(stuff.answer).to eq(42)
end

delayed

Use delayed { ... } to verify expectations after test example and its after hooks finish. Example:

it "does something interesting eventually" do
  delayed { expect(value).to eq(42) }
  # .. do something else, that should eventually lead to value == 42 ..
end

Custom matchers

First, define your matcher implementing this protocol:

class MyMatcher(T, E)
  include Spec2::Matcher

  @actual_inspect : String?

  def initialize(@expected : T, @stuff : E)
  end

  def match(actual)
    @actual_inspect = actual.inspect

    # return true or false here
  end

  def failure_message
    "Expected to be valid #{@stuff.inspect}.
    Expected: #{@expected.inspect}.
    Actual:   #{@actual_inspect}."
  end

  def failure_message_when_negated
    "Expected to be invalid #{@stuff.inspect}.
    Expected: #{@expected.inspect}.
    Actual:   #{@actual_inspect}."
  end

  def description
    "(stuff in #{@expected} #{stuff})"
  end
end

And then, register shortcut helper method to use your matcher.

Spec2.register_matcher(stuff) do |stuff, expected|
  MyMatcher.new(expected, stuff)
end

And use it:

describe "stuff" do
  it "is valid stuff" do
    expect(something).to stuff(some_stuff, "expected stuff")
  end
end

Development

After you forked the repo:

  • run crystal deps to install dependencies
  • run crystal spec and crystal unit to see if tests are green (or just run scripts/test to run them both)
  • apply TDD to implement your feature/fix/etc

Contributing

  1. Fork it ( https://github.com/waterlink/spec2.cr/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Contributors

  • waterlink Oleksii Fedorov - creator, maintainer

More Repositories

1

rack-reverse-proxy

A Reverse Proxy for Rack
Ruby
194
star
2

active_record.cr

Active Record pattern implementation for Crystal.
Crystal
191
star
3

Challenge-Build-Your-Own-Array-In-Js

This is a challenge that will allow you to practice your logical, analytical and problem-solving skills. Additionally, by the end of it you’ll have much better command of arrays in javascript.
JavaScript
177
star
4

rspec-json_expectations

Set of matchers and helpers to allow you test your APIs responses like a pro.
Gherkin
138
star
5

mocks.cr

General purpose mocking library for Crystal.
Crystal
51
star
6

crystal-mysql

Basic mysql bindings for crystal.
Crystal
32
star
7

timecop.cr

Mock with `Time.now` with the power of time travel, time freeze and time scale.
Crystal
19
star
8

refactoring-koans-js

Refactoring Koans to help you learn to refactor code smells in javascript
JavaScript
17
star
9

query.cr

Query abstraction for Crystal Language. Used by active_record.cr library.
Crystal
13
star
10

quick.cr

QuickCheck implementation for Crystal Language
Crystal
11
star
11

kotlin-spring-boot-mvc-starter

This is a starter repository for work with Kotlin on Back-end using Spring Boot 2 MVC, JdbcTemplate, Thymeleaf, Emails with Thymeleaf templates, Spring Security, Feature/UI tests using Fluentlenium, Clean Controller->Service->Repository pattern that is a sweet spot as your starting architecture. Includes a small demo in its source code.
Kotlin
11
star
12

postgres_adapter.cr

Postgres adapter for [active_record.cr](https://github.com/waterlink/active_record.cr). Uses [crystal-pg](https://github.com/will/crystal-pg) driver.
Crystal
9
star
13

spec2-mocks.cr

This library connects spec2.cr and mocks.cr, effectively enabling 'have_received' expectation for spec2.
Crystal
8
star
14

expand.cr

Crystal tool for macro debugging. Allows one to expand macro recursively.
Shell
6
star
15

mysql_adapter.cr

Mysql adapter for [active_record.cr](https://github.com/waterlink/active_record.cr). Uses [crystal-mysql library](https://github.com/waterlink/crystal-mysql)
Crystal
6
star
16

timestamp.cr

Timestamps in crystal-lang. Adds `.from_timestamp` and `#to_timestamp` methods to `Time`
Crystal
5
star
17

quizzykotlin

An example application for my free Getting Started With Kotlin Tutorial
Kotlin
4
star
18

rebecca

Simple database convenience wrapper for Go language.
Go
4
star
19

BuildYourOwnTestingFrameworkPart1

This is a source code for the first part of "Build Your Own Testing Framework" series
JavaScript
4
star
20

singleton.cr

Singleton library for Crystal Language.
Crystal
3
star
21

devpoll

devpoll - small web application for making polls written in http://crystal-lang.org/ (Crystal lang)
Crystal
3
star
22

aop

Very thin AOP gem for Ruby
Ruby
3
star
23

four-cycles-of-tdd-lightning-talk

Slides for my lightning talk: 4 Cycles of Test-Driven Development
HTML
3
star
24

money_tracking

CLI tool for tracking your expenses.
Ruby
2
star
25

restricted_struct

RestrictedStruct gem: create Struct-s with private or protected attributes
Ruby
2
star
26

contracts-rspec

Plugin for contracts.ruby that fixes issues with rspec-mocks.
Ruby
2
star
27

openproject-docker

Let OpenProject run in a docker container
Shell
2
star
28

race-conditions-testing-example

Kotlin
2
star
29

plugged

Library for writing extendable CLI applications for Golang.
Go
2
star
30

tspp_project

C++
2
star
31

messenger-ES6

JavaScript
1
star
32

goactor

Thin Actor implementation in Golang
Go
1
star
33

confident.ruby

Be confident and narrative when writing code in ruby
Ruby
1
star
34

secrets

Simple bash script to manage your secrets with symmetric key.
Shell
1
star
35

es-snapshot

This is a small script to make an elasticsearch snapshot. Tested with TDD in Bash in a very esoteric way.
Shell
1
star
36

crystal-blog

Simple blog in crystal using frank and active_record.cr
Crystal
1
star
37

cars-droid

Clojure
1
star
38

ShellTools

My bash shell tools. Unit-tested.
Shell
1
star
39

likes

Give it a list of people and their likings and it will tell what else could these people like. Ruby gem.
Ruby
1
star
40

docker-elasticsearch-kubernetes-aws

Docker image for elasticsearch with support for Kubernetes and AWS cloud
Shell
1
star
41

namegen.cr

This library provides facilities for generating random names/nicknames. Written in Crystal-Lang.
Crystal
1
star
42

stomp

Example game engine in Ruby. Uses Component Entity System + World paradigm.
Ruby
1
star
43

tdd-talk-ru

TDD talk (version in Russian, for Top-Engineer webinar). | Доклад о TDD, для вебинара Top-Engineer.
HTML
1
star
44

elm-todo

Simple ToDo application written in Elm lang. No backend (yet?).
Elm
1
star
45

explorative-tdd-talk

CSS
1
star
46

gas-template

Google Apps Script template for more comfortable development on local machine. Plus CI/CD included.
Shell
1
star
47

LoginSignupE2E

Example project for the blog post "Learning TDD with JS: End-to-End Testing". Implements Login and Signup for a web-application using TDD and E2E feature tests.
JavaScript
1
star
48

cars_api

Ruby
1
star
49

strong_ruby

Just playing around with strong typing in Ruby
Ruby
1
star
50

property-based-testing-talk

HTML
1
star
51

contracts-non_intrusive

Less intrusive version of Contracts DSL. Allows to use static/dynamic code analysis tools.
Ruby
1
star
52

recorder

Daemon that records all incoming HTTP request and allow to fetch them and put expectations on them. Useful for CLI tools testing.
Go
1
star