Sunday, February 27, 2011

Another release for Fluent Assertions

It’s only February, but I’ve received so many requests from the community that another release of Fluent Assertions was easily warranted.

New Features

  • Somebody working under the name of CtrlAltDel pointed me at the little-known fact that floating point variables are inheritably inaccurate and should never be compared for equality (read this article for a better explanation). Consequently Should().Be() and Should().NotBe() are no longer available for floats and doubles anymore. Instead, use the following method specifically designed for comparing floating point variables.

    float value = 3.1415927F;
    value.Should().BeApproximately(3.14F, 0.001F
    );

    This will verify that the value of the float is between 3.139 and 3.141.
  • As part of dealing with floating point comparison, I’ve also added a BeInRange() method available for all numeric types (both integral as well floating point based).

    theInt.Should().BeInRange(1,10);
  • The assertions currently offered for all (nullable) integral types are now also available for bytes and shorts.
  • With version 1.4, you no longer have to use the TimeSpan class directly and can instead use extension methods to convert a number to a TimeSpan.

    theDatetime
      .Should()
      .BeLessThan(10.Minutes())
      .Before(otherDatetime);

    Other examples include 10.Minutes(), 2.Hours(), 1.Days(), 2.Days() and even 600.Milliseconds()
  • As part of a patch, Ruben Rorije introduced a set of dedicated methods that apply to TimeSpans directly:

    timespan.Should().Be(12.Hours());
  • In earlier versions it was possible to include an assertion on an exception property using the .And. property. Jonne Kats proposed an alternative syntax for doing the same by chaining or more calls to the Where() method

    Action act = () => subject.Foo(null));

    act
      .ShouldThrow<ArgumentNullException>()
      .Where(e => e.Message.StartsWith(“did”));

    You can chain multiple calls to Where to further restrict the assertion.
  • In version 1.3 I introduced a very convenient syntax for asserting that a particular event was raised. You can now also do the opposite; asserting that a particular event was not raised.

    subject
      .ShouldNotRaisePropertyChangeFor(x => x.SomeProperty);

    And if your project is .NET 3.5 or 4.0 based, you can do that with any kind of event.

    subject.ShouldNotRaise(“SomeOtherEvent”);
  • Based on an idea by Ruben Rorije, I’ve introduced a method to assert that the execution time of a particular method or action does not exceed a predefined value. To verify the execution time of a method, use the following syntax:

    var subject = new SomePotentiallyVerySlowClass();

    subject
      .ExecutionTimeOf(s => s.ExpensiveMethod())
      .ShouldNotExceed(500.Milliseconds());


    Alternatively, to verify the execution time of an arbitrary Action, use this syntax:

    Action someAction = () => Thread.Sleep(510);

    someAction
      .ExecutionTime().ShouldNotExceed(100.Milliseconds());

    Since it doesn’t make sense to do something like that in Silverlight, it is only available in the .NET 3.5 and .NET 4.0 versions of Fluent Assertions.

Breaking Changes

  • To clean up the project, I’ve moved the assertion classes to a dedicated folder, and consequently, to a different namespace. So if you’ve been extending the built-in assertion classes, you may have to fix some namespace references.

Improvements / Bugs Fixed

  • Fixed a bug where, under very specific circumstances, it seems that the Garbage Collector was cleanup up some of the data structures needed for the event monitoring functionality.
  • For those already extending Fluent Assertions, I’ve introduced a fluent syntax for the internal validation logic and harmonized failure message generation:
    Execute.Verification
    .ForCondition(Subject != null)
    .BecauseOf(reason, reasonArgs)
    .FailWith("Expected object not to be {1}{0}", null);




You can download this new release from its CodePlex page, or, if you are as enthusiastic about NuGet as I am, simply get it using the Add Library Package Reference option from within Visual Studio.