crystal
crystal copied to clipboard
Spec expectation method to match similar collections
I find myself doing something like this a lot in my specs, and figured it might be a cool addition.
results = [1, 2, 3, 4]
results.should contain(2)
results.should contain(4)
results.should_not contain(5)
results.should_not contain(0)
Maybe the contain could take a splat? or we could have a new method to handle this?
results.should contain(2, 4)
results.should_not contain(5, 0)
results.should have([2, 4])
results.should_not have([5, 0])
Something like this could probably also work for hashes
results = {"id" => "1234", "key" => "sdfhu3", "code" => "xxxx"}
results.should have({"key" => "sdfhu3", "code" => "xxxx"})
results.should_not have({"pass" => "@", "item" => "G12"})
I believe Rspec supports this though, I'm sure it's probably done with some Ruby meta magic :zany_face: lol
Adding a splat arg to contain looks easy enough. It won't support dynamic collections, but that's probably fine for the spec use case.
On the other hand, I'm not sure how useful that really is... In practice, for positive expectations I'd rather be more specific about the exact collection (or sub-collection if it's to much burdon to cover the whole) for most typical use cases.
results = [1, 2, 3, 4]
results.should eq [1, 2, 3, 4]
# or
results[1, 3].should eq [2, 3, 4]
# or
results[1].should eq(2)
results[3].should eq(4)
So I'd be interested in concrete use cases for a collection inclusion expectation.
So I'd be interested in concrete use cases for a collection inclusion expectation.
Sure.
it "returns a list of my friends, with some random users added in" do
# lots of setup stuff
results = graph_query.fetch_user_list(current_user)
usernames = results.map(&.username)
# I only care that these 3 are in the list, but the list has more than 3
(usernames.size > 3).should be_true
usernames.should contain("friend1")
usernames.should contain("friend2")
usernames.should contain("friend3")
end
It would be kinda cool if I could just do
usernames.should contain("friend1", "friend2", "friend3")
I think users should be able to write their own expectation classes for the standard library's Spec. (I did this once for the compiler's own specs.) The expectation object's interface is apparently not documented yet. Here is an example:
require "spec"
private record ContainManyExpectation(*T), values : T do
def match(actual_value) : Bool
@values.all? { |value| actual_value.includes?(value) }
end
# failure message used by `should`
def failure_message(actual_value) : String
"Expected: ..."
end
# failure message used by `should_not`
def negative_failure_message(actual_value) : String
"Expected: ... not to ..."
end
end
def contain_many(*values : *T) forall T
ContainManyExpectation(*T).new(values)
end
it { (6..).should contain_many(5, 7, 1000) } # should fail