Closed ianwhite closed 11 years ago
Thinking about this a bit more, I can see we need to distinguish the outer block in my example, from the two inner blocks. We don't want to run the invariant in the outer block, it's a setup block. The innermost blocks are leafs, and this could be the criteria for triggering invariants.
An Invariant is run after every When
, or on innermost contexts with no When
Since Whens are often hoisted out into setup blocks, running invariants after a when is probably not a good idea either.
However, I can see running invariants on the inner-most blocks, even if there is no then.
The problem is that I'm not sure RSpec gives sufficient hooks in order to detect that condition (we would need some kind of end-of-context hook). If you want to investigate, please do. I would be happy to hear your results.
Thanks for your reply. I mis-commented above, I meant to say:
An Invariant is run after every Then
, or on innermost contexts with no Then
I shall investigate whether rspec provides enough infrastructure for this.
As you say, there is no public api provided by rspec to detect this condition.
The best I can come up with is that specifying an invariant creates an example (it) that conditionally runs depending on whether there is a nested child group (done in a very hackish and highly coupled to rspec internals way: testing if self.class::Nested_1
is defined).
This is too hacky, so I'm closing this ticket.
However, a much simpler approach is to create a different context. For example, I load this file from my spec helper:
require 'rspec/given'
RSpec::Given.use_natural_assertions
module RunInvariants
def run_invariants(*args, &block)
context(*args) do
block && block.call
Then { true }
end
end
end
RSpec.configure do |config|
config.extend(RunInvariants)
end
Which can be used like:
describe "one element things" do
Given(:subject) { [:a] }
Invariant { subject.length == 1 }
run_invariants "1 elem Array"
run_invariants "1 elem Hash" do
Given(:subject) { {a: 1} }
end
end
If you are interested in adding this to rspec-given, I can work on a patch. I'm not massively happy with run_invariants
as a name, but can't think of anything better right now.
Hi Jim,
Saw your scotruby talk, and thought I'd given rspec-given a try, and I'm loving it!
I would like to be able to specify some invariants, and then specify some nested setup contexts, and watch it go. E.g.
Running this spec shows 0 examples.
Adding
Then { true }
at the bottom of each context has the desired effect.Would you be open to adding an implicit
Then
to empty contexts which have Invariants defined, so as to trigger them? And if so, do you think detecting this (no thens but some invariants) is possible in rspec? If so, I'll start on a patch.(I have achieved the effect I want by using shared examples, but I like the idea of being able to set up invariants about a case, then specify a number of ways of getting to that case)
Cheers, Ian White