1

This may be a naive question, but does RSpec's testing DSL violate the law of Demeter?

Here's an example of the RSpec DSL from http://rspec.info:

bowling.score.should eq(0)

From a Demeter perspective, this seems to me indistinguishable from this example:

user.department.try(:name)

which according to Avdi Grimm is a violation of the Law of Demeter.

Source: http://devblog.avdi.org/2011/07/05/demeter-its-not-just-a-good-idea-its-the-law/

dan
  • 43,914
  • 47
  • 153
  • 254
  • Just a note, that is the documentation for RSpec 1, which is probably not what you want. RSpec 2 lives at http://relishapp.com/rspec. – Andrew Marshall Mar 02 '12 at 02:40
  • Thanks for the correction. I think the RSpec example is still representative though, right? – dan Mar 02 '12 at 02:42
  • Yes, it is. The RSpec 1 site is annoyingly lacking any link to the RSpec 2 docs, though, which can cause lots of confusion. – Andrew Marshall Mar 02 '12 at 02:44

2 Answers2

2

Demeter is a risk-reduction guideline motivated by the idea that the less one part of the system depends on the structure of other parts, the less likely that part will be impacted by changes to said structure.

You could certainly argue that game.score.should eq(0) is a Demeter violation, but the should method is part of the rspec framework, which is the context around the statement game.score.should eq(0) and is not likely to change in a way that would force changes to this statement.

Maybe it violates Demeter, maybe it doesn't, but the risk that Demeter aims to address is not really present.

David Chelimsky
  • 8,920
  • 2
  • 38
  • 30
1

This is obviously subjective, but I believe it does not.

The should call is part of the language of RSpec, which just happens to be built upon Ruby. There's no reason it couldn't be:

should_be_equal(bowling.score, 0)

(or similar) but that's not the language of RSpec. Further, the should method only exists on that object within specs, for the specs.

To try and (somewhat crudely, perhaps) better illustrate my argument about being a part of the language:

bowling.score + 10

is actually calling the + method on score, but would you see this as a law of demeter violation? The + is seen as an operator rather than a method, much like should be above.

Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
  • What if proponents of `try` said something similar about `try`: that it should be considered a pseudo-operator, instead of a method? Would that argument hold water too? Why or why not? – dan Mar 02 '12 at 02:41
  • `try` in your example above *is* a law of demeter violation because you're essentially calling `user.department.name`, just with some protection if `department` is `nil`. `user.try(:department)`, though, would not violate the law of demeter. – Andrew Marshall Mar 02 '12 at 02:43
  • That makes sense. So are you saying that Ruby DSLs are exempt from having to follow the Law of Demeter? – dan Mar 02 '12 at 02:55
  • It probably depends. When you're trying to express something as a language, it's not really so much a method call on the object. Further, law of demeter doesn't really matter as much in tests in the first place: I think if you're doing unit tests properly it will encourage you to flush out law of demeter violations in your code because they make mocking/stubbing much more difficult. – Andrew Marshall Mar 02 '12 at 02:58
  • OK I think I'm satisfied with that. – dan Mar 02 '12 at 03:01