MSpec v0.2

EDIT:Machine, including MSpec are now hosted on github: http://github.com/machine/machine

It’s been a while, but we’ve gotten several new things into Machine.Specifications (MSpec). I’m excited to finally release them for everyone to start playing with. Don’t know what MSpec is? Please, read my original post. You can grab the bits here.

Let’s talk about what’s new though. Here’s an example of a new context/spec:

  [Concern("Console runner")]
  public class when_specifying_a_missing_assembly_on_the_command_line
  {
    Establish context = ()=>
    {
      console = new FakeConsole();
      program = new Program(console);
    };

    Because of = ()=>
      exitCode = program.Run(new string[] {missingAssemblyName});

    It should_output_an_error_message_with_the_name_of_the_missing_assembly = ()=>
      console.Lines.ShouldContain(string.Format(Resources.MissingAssemblyError, 
      missingAssemblyName));

    It should_return_the_Error_exit_code = ()=>
      exitCode.ShouldEqual(ExitCode.Error);

    const string missingAssemblyName = "Some.Missing.Assembly.dll";
    public static ExitCode exitCode;
    public static Program program;
    public static FakeConsole console;
  }

There have been a few semantic changes

  • The Description attribute has been removed. There is now an optional Concern attribute that allows you to specify a type and/or a string that the context/spec is concerned with.
  • Context before_each is now Establish context.
  • Context before_all is now Establish context_once.
  • Context after_each is now Cleanup after_each.
  • Context after_all is now Cleanup after_each.
  • When {…} is now Because of. This is closer to SpecUnit.NET’s verbage, and doesn’t force you to specify the “when” twice.

There is now a console runner

We don’t quite have all the options we want yet, but the basics of the runner are working. Here’s the help from the runner:

We also stole Bellware’s SpecUnit.NET reporting stuff and ported it over. You can now generate a report on your specs with the –html switch. Here’s an example run:

This is the report it generates.

Want to try it out?

  1. Grab the drop here.
  2. Extract it somewhere. Put it somewhere semi-permanent because the TestDriven.NET runner will need a static location for the MSpec TDNet Runner.
  3. If you want TestDriven.NET support, run InstallTDNetRunner.bat
  4. Check out the example in Machine.Specifications.Example. Note that you can run with TD.NET.
  5. Create a project of your own. Just add Machine.Specifications.dll and get started.
  6. Send me feedback! Leave comments, email me, tweet me, whatever.

Also, this is part of Machine, so feel free to take a look at the code and/or submit patches. There’s also a Gallio adapter in there, but I didn’t include it in the release as it’s not quite polished enough yet. If you’re interested in it, talk to me. Special thanks to Scott Bellware, Jeff Brown and Jamie Cansdale for their help and support. Also, extra special thanks to Eleutian’s newest dev, Jeff Olson for much of the recent work that has gone into MSpec!

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://aaron-jensen.com Aaron Jensen

    You’re using a really old version. Go to github and get the latest from there or from Nuget.

    That said, this probably isn’t the best place for questions, I’d recommend going to the user group: https://groups.google.com/forum/?fromgroups#!forum/machine_users
    You could also post on stack overflow if you have questions. 

  • http://www.facebook.com/gmpat4u Gunjan Patel

    “mspec-runner”, the commandline utility doesn’t work – my assembly is “Machine.Specifications.dll” and the location is “C:DataractLibsmspec_01Machine.Specifications.ExamplebinDebug”…

    I run following command…

    mspec-runner Machine.Specifications.dll –html out.html

    Output…

    Specs in Machine.Specifications:

    C:DataractLibsmspec_01Machine.Specifications.ExamplebinDebug>

    Nothing in output and next prompt…

    !?!??!? Any solution?

  • http://aaron-jensen.com Aaron Jensen

    You should take a look at the github, the syntax has changed. The syntax in your parens is old: http://github.com/machine/machine

  • http://www.facebook.com/gmpat4u Gunjan Patel

    Hi, this is very cool… Can someone please tell me where can I find some document for this where I should read the meaning and difference of…

      – Establish context ( Context before_each )
      – Establish context_once ( Context before_all )
      - Cleanup after_each ( Context after_each )
      - Cleanup after_each ( Context after_all )
      - Because of ( When {…} )

  • http://codebetter.com/members/aaronjensen/default.aspx aaronjensen

    Thanks! The best thing to do is to either use the R# runner or the TD.net runner and run with debugging. Otherwise, you can put a Debugger.Breakpoint() wherever you want to break in your code. *or* (I think) you can set your executable for your test assembly to be the mspec runner w/ appropriate commandline parameters, set it to the startup project, add some breakpoints and just hit f5. Hope that helps!

  • Paul

    Love MSpec, but can’t figure out how to get the built-in test runner to run it with debugging. Any advice?

  • http://www.corebvba.be Tom Janssens

    Hey Aaron,
    First of all : I really appreciate your work on MSpec; it conviced me to try out BDD for the first time in .Net/c#, and I must admit I like it a lot.
    Just wanted to mention you that I have written a few articles over on my blog on how to get started with MSpec, together with asp.net mvc, FluentNhibernate, Castle Windsor and Git; you can find it here : http://www.corebvba.be/blog/?tag=/w00t

    Kind regards,
    Tom

  • http://codebetter.com/members/aaronjensen/default.aspx aaronjensen

    Arthur,

    Unfortunately, generics are not supported in attributes at the moment. Wish they were :)

  • http://codebetter.com/members/kodart/default.aspx kodart

    I got it!

    Another suggestion is regarding Behaves_like that I saw in an article on EleganceCode (http://elegantcode.com/2009/07/05/mspec-take-2/)

    We can see unnecessary repetition:
    Behaves_like no_sales_tax_added;

    It is better to introduce and apply attribute:
    [Behaves_like]

    Actually do the same for
    [Concern(typeof(Account), "Funds transfer")]
    =>
    [Concern("Funds transfer")]

    Regards Arthur

  • http://codebetter.com/members/aaronjensen/default.aspx aaronjensen

    kodart,

    Preparation is mutation. I was not talking about not mutating in the context though, I was talking about not mutating in the specifications (It).

    I do not create a new context for each specification. Before each or Establish context as it’s called now, is in fact a set up, but as I stated, it only needs to be set up once because the specifications should be read-only aka not mutate state.

  • http://codebetter.com/members/kodart/default.aspx kodart

    Actually, I’m preparing state in [before each], not mutating it.

    Otherwise, where do you suggest to prepare the state?

  • http://codebetter.com/members/kodart/default.aspx kodart

    Before each is a kind of setup isn’t it? Or do you create a new instance of test class before running each test?

    So the question is: why we don’t need before each?

  • http://codebetter.com/members/aaronjensen/default.aspx aaronjensen

    Actually, this post isn’t even the latest. I just realized you were talking about Establish context and context_once. The once nomenclature is gone for reasons I previously described.

  • http://codebetter.com/members/aaronjensen/default.aspx aaronjensen

    In my experience, there is no real need for Before each. If you need Before each, you are doing something in your observations that is mutating state. That, by definition, is not an observation. I allow for this if you really need it by adding an attribute.

    As for the actual wording, I (and others that I’ve discussed it with) feel that the current wording is more descriptive and intention revealing.

  • http://www.kodart.com Arthur

    Hi, just saw your update.

    Why did you decide to introduce: Establish context, Cleanup, etc. ?

    I would suggest:

    Before each = () => {…}
    Before all = () => {…}

    same for: After each/all

    Best regards,
    Arthur

  • http://codebetter.com/members/aaronjensen/default.aspx aaronjensen

    If you only need to do it once (like set up something expensive) you can use an AssemblyContext. Just implement IAssemblyContext in a class in one of your spec assemblies and MSpec will invoke it. Hope that helps.

  • Tad

    Hi,
    Thanks for information :) I have one more question, is it possible to have only one setupFixture which would execute only once for many tests (test classes)? I would like to have one base class with context and execute that context only once and share it beetween test classes , but don’t know if it possible

  • http://codebetter.com/members/aaronjensen/default.aspx aaronjensen

    Hi Tad,

    The documentation in this post is a bit out of date. The context is executed once and only once regardless of what you name it. If you want it to execute before each specification you can add the SetupForEachSpecification attribute to your context, though I strongly advise against it. Specifications are meant to be observations. Observations do not mutate state. There is no reason to set up the context more than once if you’re adhering to this guidance.

  • Tad

    Hi,
    I’m using MSpec right now but found very strange “bug”, it doesn’t make difference if I use Establish context or Establish context_once becuse it is executed only once and for cleanup is the same , it it appropriate behavoiur ?

  • http://www.pseale.com/blog/ Peter

    I’m not sure if this was something I did or something I should have done. I should start by describing what I did at first, then describing how I enabled TD.NET integration:

    1. Downloaded MSpec (specifically Machine.Specifications from the Machine page) from Github.
    2. Opened Machine.Specifications.sln, F5 built it.
    3. Oops, cleaned out Debug dir, switched to Release mode, F5 built it.
    4. Copied entire source/distro/everything to %PROGRAMFILES%\mspec
    5. Found Distribution\Specifications\ directory and ran InstallTDNetRunner.bat

    … this is when I reported the problem. Step 6 (fixed the problem) is:

    6. Copied Machine.Specifications.TDNetRunner.dll from Release\ folder to the Distribution\Specifications\ folder (this is where batch file/registry hack in #5 told TD.NET to look)

    Anyway thanks for your attention, this is resolved.

  • Joe Ocampo

    This is really awesome. I will have put it through it’s paces.

  • http://www.scottcreynolds.com Scott

    Looks awesome man, I’ll grab it and run it through its paces this week! I’m glad you guys (you and Scott) put your heads together. Thanks!