Updated Release: Release 2.0.0 (Oct 07, 2012)
Source code checked in, #cabfb3c5aa73
Updated Wiki: Home
Project Description
Fluent Assertions is a set of .NET extension methods that allow you to more naturally specify the expected outcome of a TDD or BDD-style test. We currently use it in all our internal and client projects, and it is used in many open-source projects. It runs on .NET 3.5, 4.0 and 4.5 (Desktop and Windows Store), Silverlight 4 and 5 and Windows Phone 7.5. And it supports the unit test frameworks NUnit, XUnit, MBUnit, Gallio and MSpec.
Why?
Nothing is more annoying then a unit test that fails without clearly explaining why. More than often, you need to set a breakpoint and start up the debugger to be able to figure out what went wrong. Jeremy D. Miller once gave the advice to "keep out of the debugger hell" and I can only agree with that.
For instance, only test a single condition per test case. If you don't, and the first condition fails, the test engine will not even try to test the other conditions. But if any of the others fail, you'll be on your own to figure out which one. I often run into this problem when developers try to combine multiple related tests that test a member using different parameters into one test case. If you really need to do that, consider using a parameterized test that is being called by several clearly named test cases.
That’s why we designed Fluent Assertions to help you in this area. Not only by using clearly named assertion methods, but also by making sure the failure message provides as much information as possible. Consider this example:
"1234567890".Should().Be("0987654321");
This will be reported as:
The fact that both strings are displayed on a separate line is on purpose and happens if any of them is longer than 8 characters. However, if that's not enough, all assertion methods take an optional formatted reason with placeholders, similarly to String.Format,
that you can use to enrich the failure message. For instance, the assertion
new[] { 1, 2, 3 }.Should().Contain(item => item > 3, "at least {0} item should be larger than 3", 1);
Examples
To verify that a string begins, ends and contains a particular phrase.
string actual = "ABCDEFGHI"; actual.Should().StartWith("AB").And.EndWith("HI").And.Contain("EF").And.HaveLength(9);
To verify that a collection contains a specified number of elements and that all elements match a predicate.
The nice thing about the second failing example is that it will throw an exception with the message
IEnumerable collection = new[] { 1, 2, 3 }; collection.Should().HaveCount(4, "because we thought we put three items in the collection"))
collection.Should().Contain(i => i > 0);
"Expected <4> items because we thought we put three items in the collection, but found <3>."
To verify that a particular business rule is enforced using exceptions.
var recipe = new RecipeBuilder() .With(new IngredientBuilder().For("Milk").WithQuantity(200, Unit.Milliliters)) .Build(); Action action = () => recipe.AddIngredient("Milk", 100, Unit.Spoon); action .ShouldThrow<RuleViolationException>() .WithMessage("change the unit of an existing ingredient", ComparisonMode.Substring) .And.Violations.Should().Contain(BusinessRule.CannotChangeIngredientQuanity);
What’s new?
Another release with lots of bug fixes and small improvements and with great contributions by Martin Opdam and Urs Enzler. Download it here or get it through NuGet.
About versioning
The version numbers of Fluent Assertions releases comply to the Semantic Versioning scheme. In other words, release 1.4.0 only adds backwards-compatible functionality and bug fixes compared to 1.3.0. Release 1.4.1 should only include bug fixes. And if we ever introduce breaking changes, the number increased to 2.0.0.
Who are we?
If you have any comments or suggestions, please let us know via twitter, through the discussions page, or through StackOverflow.
#fluentassertions |
Updated Wiki: Home
Project Description
Fluent Assertions is a set of .NET extension methods that allow you to more naturally specify the expected outcome of a TDD or BDD-style test. We currently use it in all our internal and client projects, and it is used in many open-source projects. It runs on .NET 3.5, 4.0 and 4.5 (Desktop and Windows Store), Silverlight 4 and 5 and Windows Phone 7.5. And it supports the unit test frameworks NUnit, XUnit, MBUnit, Gallio and MSpec.
Why?
Nothing is more annoying then a unit test that fails without clearly explaining why. More than often, you need to set a breakpoint and start up the debugger to be able to figure out what went wrong. Jeremy D. Miller once gave the advice to "keep out of the debugger hell" and I can only agree with that.
For instance, only test a single condition per test case. If you don't, and the first condition fails, the test engine will not even try to test the other conditions. But if any of the others fail, you'll be on your own to figure out which one. I often run into this problem when developers try to combine multiple related tests that test a member using different parameters into one test case. If you really need to do that, consider using a parameterized test that is being called by several clearly named test cases.
That’s why we designed Fluent Assertions to help you in this area. Not only by using clearly named assertion methods, but also by making sure the failure message provides as much information as possible. Consider this example:
"1234567890".Should().Be("0987654321");
This will be reported as:
The fact that both strings are displayed on a separate line is on purpose and happens if any of them is longer than 8 characters. However, if that's not enough, all assertion methods take an optional formatted reason with placeholders, similarly to String.Format,
that you can use to enrich the failure message. For instance, the assertion
new[] { 1, 2, 3 }.Should().Contain(item => item > 3, "at least {0} item should be larger than 3", 1);
Examples
To verify that a string begins, ends and contains a particular phrase.
string actual = "ABCDEFGHI"; actual.Should().StartWith("AB").And.EndWith("HI").And.Contain("EF").And.HaveLength(9);
To verify that a collection contains a specified number of elements and that all elements match a predicate.
The nice thing about the second failing example is that it will throw an exception with the message
IEnumerable collection = new[] { 1, 2, 3 }; collection.Should().HaveCount(4, "because we thought we put three items in the collection"))
collection.Should().Contain(i => i > 0);
"Expected <4> items because we thought we put three items in the collection, but found <3>."
To verify that a particular business rule is enforced using exceptions.
var recipe = new RecipeBuilder() .With(new IngredientBuilder().For("Milk").WithQuantity(200, Unit.Milliliters)) .Build(); Action action = () => recipe.AddIngredient("Milk", 100, Unit.Spoon); action .ShouldThrow<RuleViolationException>() .WithMessage("change the unit of an existing ingredient", ComparisonMode.Substring) .And.Violations.Should().Contain(BusinessRule.CannotChangeIngredientQuanity);
What’s new?
Another release with lots of bug fixes and small improvements and with great contributions by Martin Opdam and Urs Enzler. Download it here or get it through NuGet.
About versioning
The version numbers of Fluent Assertions releases comply to the Semantic Versioning scheme. In other words, release 1.4.0 only adds backwards-compatible functionality and bug fixes compared to 1.3.0. Release 1.4.1 should only include bug fixes. And if we ever introduce breaking changes, the number increased to 2.0.0.
Who are we?
If you have any comments or suggestions, please let us know via twitter, through the discussions page, or through StackOverflow.
#fluentassertions |
Updated Wiki: Temporary Post Used For Theme Detection (2ca91bfc-29a6-40c3-b1b6-b106ff551f3c - 3bfe001a-32de-4114-a6b4-4005b770f6d7)
This is a temporary post that was not deleted. Please delete this manually. (13389238-c4d2-466f-a886-d0c3655d1a79 - 3bfe001a-32de-4114-a6b4-4005b770f6d7)
Source code checked in, #5917d76e4bcd
Source code checked in, #7d21627804d4
New Post: Optional arguments in 2.0 break method usage in expressions
Congratulations on the 2.0 release - some really exciting new features in there!
I have one complaint however :-(
- All overloads that took the reason and reasonargs parameters have been removed and replaced with optional parameters
I am the author of the xBehave.net project (https://github.com/xbehave/xbehave.net). One of the features of xBehave.net is that you can pass assertions as expressions and xBehave.net will automatically generate a natural language representation for the test output. E.g.
"When pushing the element onto the stack"
.When(() => stack.Push(element))
.Then(() => stack.Should().NotBeEmpty());
With FluentAssertions < 2.0, this renders as "When pushing the element onto the stack, Then the stack should not be empty".
However, since NotBeEmpty() has an optional argument in FluentAssertions 2.0, the expression stack.Should().NotBeEmpty() can no longer be passed as an Expression and the above code will no longer compile.
Personally I consider optional arguments to be a real can of worms and there was, justifiably, a long period of strong resistance from the C# at Microsoft to introducing them. I didn't realise that optional arguments in methods prevented construction of expressions containing calls to those methods but this is yet another reason in the long list of many for not using optional arguments. I realise that it's probably too late to consider a backout of this change in FluentAssertions but I wonder what your thoughts are on this? I guess the only way around this would be to provide pseudonym methods with no optional arguments but I suppose that would be quite messy.
New Post: Optional arguments in 2.0 break method usage in expressions
Hi Adam,
Thanks for taking the time to explain your problem. I've been in that same 'camp', at least, until recently. My C# Coding Guidelines still recommend not doing that, but since its introduction in C# I never ran into a situation that proved that recommendation still made sense. It would be very painful to re-add all those overloads, especially after removing them so recent ;-)
Do you know of any alternatives that might keep your syntax intact as much as possible?
Released: Release 2.0.0 (Oct 07, 2012)
Updated Release: Release 2.0.0 (Oct 07, 2012)
New Post: Equals cannot match generic List correctly
I just upgraded to 2.0 and I have following code to test list values
actualResponse.MyObject.Group .Should().NotBeEmpty() .And.Should().NotBeNull() .And.Should().Equals(new List<string> { "group1", "group2" });
MyObject.Group has data type of List<string>, no matter what values I have in Equals, the test always passes.
New Post: Equals cannot match generic List correctly
Hi Hardywang,
I think your problem is caused by the fact that you are using Equals() rather than Equal(). You are now calling the built-in Object.Equals method every object inherits from System.Object.
New Post: Optional arguments in 2.0 break method usage in expressions
Hi Dennis,
After giving it some thought, I think I may just remove the Expression overloads from xBehave.net. It was fun code to write, but I only ever gave it 'experimental' status in the documentation and I was never 100% sure if it ought to ship as part of version 1.0 (hopefully before the end of this month).
FluentAssertions is my favourite fluent assertions lib and I use it extensively but I really don't expect you to back out all those optional parameters now! More generally, you or any other lib author are quite at liberty to introduce optional parameters wherever it makes sense and any xBehave.net steps using expressions will always be at the mercy of this. As you say, regardless of any opinions, optional parameters are a well embedded and popular language feature now and I think it's now more the case that expression usage is the more unusual of the two. Expressions were primarily introduced for LINQ providers and other usages of them are really just piggy backing off that. It's a bit of a shame since it was quite a handy feature in xBehave.net but it's no great loss.
Keep up the good work!
New Post: Optional arguments in 2.0 break method usage in expressions
Pfew, I really wasn't looking forward to all that work :-)
But seriously, thanks for the trust and compliments. That's what keeps open-source projects fun.
Commented Issue: HaveElement should support XNames [12453]
Comments: Playing with this one on the fork: http://fluentassertions.codeplex.com/SourceControl/network/forks/ikhavkin/xnamesupport
New Post: Comparing two similar objects fails
Hi,
when i'm comparing two matching objects, the assertion fails.
any idea why?
Expected property InFieldOffset to be
Data.Recipe.FieldOffset { Column = 1 Row = 1 },
but found
Data.Recipe.FieldOffset { Column = 1 Row = 1 }.
I'm using version 1.7.1.
class is defined as follows:
[Serializable]
public class FieldOffset
{
public FieldOffset(int row, int column)
{ Row = row; Column = column; }
public int Row { get; set; }
public int Column { get; set; }
}
Thanks!
Source code checked in, #3e69c694b236
Source code checked in, #832f67ed7758
New Post: Comparing two similar objects fails
How are you comparing them?