It’s always bittersweet to say that you have introduced a breaking change in an API that people use. Bitter because it will break peoples code. But sweet because IT’S AN AWESOME NEW FEATURE!
I was never really fond of the fact that argument constraints relies on implicit casting in FakeItEasy, this is why you had to write A<IFormattable>.Ignored.Argument but you could write the shorter A<string>.Ignored for non interface types. This had to be done in order for the chaining of argument constraints to work: A<string>.That.Contains(“foo”).And.Not.Contains(“bar”) for example. I thought I was pretty smart when I implemented this, it turns out though that ONCE in SEVERAL THOUSAND tests have I used this feature myself. Smart is never simple, smart is quite often stupid.
Now, I don’t wanna be stupid, so what can I do? I can remove the stupid feature. Said and done, in versions >= 1.7.* you can no longer chain argument constraints (but you weren’t doing that anyway).
Things that will break:
First of all, everything breaks at compile time so you won’t be able to build without fixing the problems. This is one of the benefits of a static type system, the complier will tell you what’s wrong!
.Argument
Any argument constraint will now return an instance of the constrained type (T) and not an ArgumentConstraint<T> as it did in previous versions. This means that there is not property .Argument so you will have to remove any calls to that property from your tests. This might be quite many calls depending on how many tests you have and what you have been testing.
ArgumentConstraint<T>
As I said this class is no more (RIP). The lowest level api for creating constraints is now the “Matches(Func<T, bool> predicate, Action<IOutputWriter> descriptionWriter)” on the IArgumentConstraintManager<T> type. You access an argument constraint manager through the A<T>.That-property. This means that you can much more easily now provide extensions to the That-property, all you have to do is to create an extension method on IArgumentConstraintManager<T> and call the Matches-method inside your extension method. Here’s an example on how the IsNull() argument constraint is implemeneted.
/// <summary>
/// Constrains an argument so that it must be null (Nothing in VB).
/// </summary>
/// <typeparam name="T">The type of the argument.</typeparam>
/// <param name="manager">The constraint manager to match the constraint.</param>
/// <returns>A dummy argument value.</returns>
public static T IsNull<T>(this IArgumentConstraintManager<T> manager) where T : class
{
return manager.Matches(x => x == null, x => x.Write("NULL"));
}
If you have extended the That-property before all your extensions will have to be rewritten to use the new API, it’s quite a simple task though and you’ll be glad that it will be much easier to create new extensions.