Classic RSpec-like .should / .should_not comparisons for Crystal's spec.
book.title.should == "Revolution"The shard adds a should and should_not without arguments to Object. The
operator that follows turns into the matching spec expectation. The standard
value.should eq(x) form keeps working next to it.
This is the Crystal version of the Ruby gem minitest-should_just_work.
Add it to your shard.yml:
development_dependencies:
should_just_work:
github: domify/should_just_work$ shards install
Require it after spec, for example in spec/spec_helper.cr:
require "spec"
require "should_just_work"
describe "Books" do
it "has a title" do
book = Book.new title: "Revolution"
book.title.should == "Revolution"
end
end| should_just_work | Crystal spec |
|---|---|
x.should == y |
x.should eq(y) |
x.should == nil |
x.should be_nil |
x.should != y |
x.should_not eq(y) |
x.should != nil |
x.should_not be_nil |
x.should =~ /y/ |
x.should match(/y/) |
x.should > y |
x.should be > y |
x.should < y |
x.should be < y |
x.should >= y |
x.should be >= y |
x.should <= y |
x.should be <= y |
A failure is reported at the line of the .should, with the same message the
standard expectation gives.
For expectations without an operator, use the standard form:
x.should be_empty, x.should contain(y), x.should be_a(Y), and so on.
Use should_not to negate any comparison:
obj.should_not == 3 # => obj.should_not eq(3)
obj.should_not =~ /regex/ # => obj.should_not match(/regex/)
obj.should_not == nil # => obj.should_not be_nilshould.raise DivisionByZeroError do
2 // 0
end
should_not.raise DivisionByZeroError do
2 // 1
end
should.raise(ArgumentError, "bad") { raise ArgumentError.new("bad") }
should.raise(ArgumentError, /ba/) { raise ArgumentError.new("bad") }should.raise with no argument catches any Exception. It uses
expect_raises, so a message string must be contained in the exception's
message and a regex must match it. It returns the exception:
ex = should.raise(KeyError) { hash["missing"] }
ex.message.should =~ /missing/should_not.raise matches the message the same way. Exceptions of other
types, or with a message that does not match, pass through, and so does a
failed should inside the block.
Crystal has no throw/catch, so the Ruby gem's should.throw has no
counterpart here.
obj.should == 2 is a comparison whose result is not used, which ameba reports
as Lint/UnusedExpression. Switch the rule off for specs in .ameba.yml:
Lint/UnusedExpression:
Excluded:
- "spec/**/*.cr"$ shards install
$ crystal spec
$ shards build ameba && bin/ameba
If should_just_work has made your specs a little nicer to read and you feel like saying thanks, you can do so through GitHub Sponsors.
(c) 2026 Priit Tark, MIT license