3
Jun
2012
SubSpec
Just a quick note to mention a new tool Peter Provost turned me onto yesterday. I am digging SubSpec. It’s another Context/Spec, BDD-ish tool that sits in the middle somewhere between executable specs and a low-level AAA simple assert model. It’s appropriate anywhere Machine Specification would be appropriate, for example.
The code below also uses Shouldly to make fluent assertions.
public class SubSpecWorks { int x = 0; [Specification] public void A_SubSpec_Test() { "Given this context" .Context(() => x = 1); "When this happens" .Do(() => x = x - 1); "This should be the result".Assert(() => x.ShouldBe(0)); "And This should be the result".Assert(() => x.ShouldBe(0)); "And This should be the result too".Assert(() => x.ShouldBe(0)); } }
Things I like include:
- I am not limited to any testing grammer as a requirements author. I can use Given, When, Then, but it’s just a string.
- Built on top of XUnit, which means it just works inside Visual Studio new (2012) test runner. No add-in runner needed. Will work with R# runner, though.
Just getting started, but digging it.
I like to explore new tools, but I have come to realize that I can do that using a test setup method and regular tests, using one class per test context… I’ve been happy with that, I don’t need any other tool, and pretty much any test framework can support it. Unless I get a significant improvement on my tests or on my results, I won’t use it.
In your example, if your first Assert up there fails, you won’t ever know if the second and third ones would pass, right? You actually have 3 asserts in one test… If you don’t want that to happen you’re going to need to separate them into separate methods/specs and then why would you need another string to tell you what you want to do? Just use the method name.
This was just a post to show a new tool. Sample code may vary.
Ok. But the point is: if use the method name to describe the actual test/assert, why would you use a string again?
Oh, okay! That’s the best part. The context can be varied throughout the class, allowing more than one test method per class (less code than MSpec). I don’t yet see how I will organize tests over a large codebase, but I am working with it today and we’ll see where the structure evolves. So far, am digging the decoupling between class and method names and the details of the specification (strings).
Each .Assert is a separate run of the Context/Do/Assert phases which will each pass/fail individually (and there’s a .Observation that doesn’t run the Context/Do multiple times).
The code is 500 lines.
The strings are a concept that works well in RSpec. Highly recommend The RSpec Book from Manning to explain the role of something like RSpec.
I’ve used SubSpec a lot. I use it with AutoFixture, which is far more important to me that SubSpec itself.
Having state outside the method is bad news – idiomatic usage is to use locals. As part of that best practice is to use static methods only.
You using the one on NuGet? Be sure to visit the site for the doc to see the Assert/Observation concept/split.
I’m a proficient Ruby developer, besides .NET (right now it’s been one Ruby, one C#, and so on), I know RSpec and other Ruby BDD style frameworks. I know why the strings are important, I just did not see why have it twice, because I did not know that each .Assert would pass/fail individually. That is really nice, and removes the whole argument I had before. Thanks for the clarification.
Maybe now we could bring it to F# or Boo script and not even need to have a class and a method, just like Ruby. 🙂
Ah, now we’re talking. So then SubSpec is just a barebones RSpec impl without fancy things like nesting of contexts etc. Obv SubSpec stuff can be written in F# but if I was looking at that, I’d be looking no further than TickSpec – well worht 5 minuts nosing (or if you can find a presentation by Phil Trelford the author that’t be well worht the time). It def removes a few parentheses etc. (And TickSpec uses pattern matching neatly to manage Cucumber style tests too).