The promis of Shalt.
Posted by Uncle Bob on 12/07/2008
When writing requirements we often use the word “shall”. In Rspec, we use the word “should”. Some folks use the word “must”. These statements create the connotation of a law, or a command.
Let’s take a very old law: “Thou shalt not kill.” There are two ways to look at this law. We could look at it as a command[ment], or … we could look at it as a promise.
Here are the two different versions:
Thou shalt not kill!
Thou shalt not kill.
The difference is in the punctuation. And what a difference it makes. One is a stern order, a demand. The other is a promise… a confident guarantee… a statement of simple truth.
Now look at these rspec statements from RubySlim. I started writing the specs this way because it was shorter; but I like the connotation of confidence and truth. “I can has cheezburger.”
describe StatementExecutor do
before do
@caller = StatementExecutor.new
end
it "can create an instance" do
response = @caller.create("x", "TestModule::TestSlim",[])
response.should == "OK"
x = @caller.instance("x")
x.class.name.should == "TestModule::TestSlim"
end
it "can create an instance with arguments" do
response = @caller.create("x", "TestModule::TestSlimWithArguments", ["3"])
response.should == "OK"
x = @caller.instance("x")
x.arg.should == "3"
end
it "can't create an instance with the wrong number of arguments" do
result = @caller.create("x", "TestModule::TestSlim", ["noSuchArgument"])
result.should include(Statement::EXCEPTION_TAG + "message:<<COULD_NOT_INVOKE_CONSTRUCTOR TestModule::TestSlim[1]>>")
end
it "can't create an instance if there is no class" do
result = @caller.create("x", "TestModule::NoSuchClass", [])
result.should include(Statement::EXCEPTION_TAG + "message:<<COULD_NOT_INVOKE_CONSTRUCTOR TestModule::NoSuchClass failed to find in []>>")
end
end
This makes we want to change all the “should’ statement into “will” statement, or “does” statements.
Posted in Uncle Bob's Blatherings
Meta 12 comments, permalink, rss, atom
Posted by Uncle Bob on 11/30/2008
I want the JetBrains and Eclipse people to automate The Saff Squeeze
omments
David Chelimsky about 2 hours later:
One thing that I’m really trying to pursue more wholeheartedly is the documentation aspect of the output we get from running code examples.
Now that RSpec allows you to nest example groups and exposes #context as an alias for #describe, I might write what you wrote something like this:
describe StatementExecutor do before do @caller = StatementExecutor.new end context "calling #create with no arguments" do it "creates an instance" do response = @caller.create("x", "TestModule::TestSlim",[]) response.should == "OK" x = @caller.instance("x") x.class.name.should == "TestModule::TestSlim" end end context "calling #create with arguments" do it "creates an instance" do response = @caller.create("x", "TestModule::TestSlimWithArguments", ["3"]) response.should == "OK" x = @caller.instance("x") x.arg.should == "3" end end context "calling #create with the wrong number of arguments" do it "does not create an instance" do result = @caller.create("x", "TestModule::TestSlim", ["noSuchArgument"]) result.should include(Statement::EXCEPTION_TAG + "message:<<COULD_NOT_INVOKE_CONSTRUCTOR TestModule::TestSlim[1]>>") end end context "calling #create when there is no such class" do it "does not create an instance" do result = @caller.create("x", "TestModule::NoSuchClass", []) result.should include(Statement::EXCEPTION_TAG + "message:<<COULD_NOT_INVOKE_CONSTRUCTOR TestModule::NoSuchClass failed to find in []>>") end end end
Running this with the nested format option:
spec spec/statement_executor_spec.rb --format nested
you’d get output like this:
StatementExecutor calling #create with no arguments creates an instance with arguments creates an instance with the wrong number of arguments does not create an instance when there is no such class does not create an instance
Of course, once seeing that output, I realize that there is something missing from the description – the fact that #create works or fails because (at least in part) the number of arguments submitted matches the number of arguments expected. So I might see this and reorganize thusly:
StatementExecutor calling #create with the expected number of arguments creates an instance (for zero args) creates an instance (for one arg) with the wrong number of arguments does not create an instance when there is no such class does not create an instance
Same examples, just renamed and reorganized – tells a more thorough and coherent story.
Not sure this addresses the dissonance you are observing between the example names and the code in the examples. I’ve toyed around with an alternate syntax that uses a function that interacts with rspec’s matchers a bit differently:
expect_that response, equals("OK")
Not sure what the right name for the method is. Could be any of #expect_that, #specify_that, #verify_that, or even #assert_that.
In light of the guideline “specify, don’t verify” I think that #expect_that is probably the right one.
WDYT?
Esko Luontola about 4 hours later:
I used to use “should” in my specs, but after a while it begun looking like just some meaningless clutter. So nowadays I don’t use the “should” word in the spec names. (Also, I haven’t found any meaningful distinction between “should” and “must”.)
Instead of writing “the ball should be round” I prefer writing “the ball is round”.
Dagfinn Reiersøl about 16 hours later:
I never liked “should” much myself. On the other hand, let’s rephrase the distinction slightly, saying that “should” states a requirement and “does” expresses a fact. Now we can see that “should” more clearly indicates that it precedes the implementation. For those of us who have been working test-first for years, that might be an unnecessary reminder, but I can see how it might be considered useful for the unwashed masses ;-)
Steve Freeman 1 day later:
I always thought that “should” was a bit non-committal, but backed off after being called a fascist (or something like that) on a mailing list. I think Chris Stevenson got it right with his TestDox approach all those years ago.
David Chelimsky 1 day later:
Steve – fascist? Ouch! I hope that wasn’t on the rspec list. And I especially hope it wasn’t me!
Edwin McConnel about 1 month later:
I really dislike the words “shall”, “should”, “will” or “would” in specs of any kind.
I think that specs should be written as if the system behaves a certain way atany given instance in time. That way the spec “magically” turns into an (potentially testable) assertion and documentation.
I used to have to read requirements docs full of “The system shall…” repeated over and over again. I would do a search and replace on my copy of the Doc file just to get rid of the phrase to make things more readable.
Tenant Screening over 2 years later:
I am looking a way to solve it. I want to study. When I come to here, I think I am in the right place. the web gives me a lot of infomation, it is very informative.
Criminal Records over 2 years later:
Not sure this addresses the dissonance you are observing between the example names and the code in the examples. I’ve toyed around with an alternate syntax that uses a function that interacts with rspec’s matchers a bit differently.
Televizoare 3d fara ochelari over 3 years later:
The code is not working for me. Any other solution?