Skip to content

Instantly share code, notes, and snippets.

@philippdolder
Last active August 29, 2015 14:17
Show Gist options
  • Save philippdolder/4b00398c1f1f136acf93 to your computer and use it in GitHub Desktop.
Save philippdolder/4b00398c1f1f136acf93 to your computer and use it in GitHub Desktop.
FA question
namespace Project1
{
using System.Collections;
using System.Collections.Generic;
using FluentAssertions;
using FluentAssertions.Execution;
using FluentAssertions.Primitives;
public static class MyOwnAssertionsExtensions
{
public static MyOwnAssertions Should(this MyType subject)
{
return new MyOwnAssertions(subject);
}
}
public class MyOwnAssertions : ReferenceTypeAssertions<MyType, MyOwnAssertions>
{
public MyOwnAssertions(MyType subject)
{
this.Subject = subject;
}
protected override string Context
{
get
{
return "mytype";
}
}
public AndConstraint<MyOwnAssertions> ContainMagic()
{
// I have some additional asserts
Execute.Assertion
.ForCondition(this.Subject.ContainsMagicString())
.FailWith("No, there's no magic here");
return new AndConstraint<MyOwnAssertions>(this);
}
public AndConstraint<MyOwnAssertions> Contain(string expected)
{
// and like to use some of the already existing ones.
// I know there is a
// public AndWhichConstraint<TAssertions, T> Contain(T expected, string because = "", params object[] reasonArgs)
// implementation in the GenericCollectionAssertions.
// And I try to just refer it to that method with something like. But this leads to a endless recursive loop, because it uses my own Contain() implementation of course.
this.Subject.Should().Contain(expected);
// this line does the job. But is it how I should do it? Not sure if I miss something.
this.Subject.As<IEnumerable<string>>().Should().Contain(expected);
return new AndConstraint<MyOwnAssertions>(this);
}
}
public class MyType : IEnumerable<string>
{
private const string Magic = "It's a kind of magic!";
private readonly List<string> strings;
public MyType()
{
this.strings = new List<string>();
}
public bool ContainsMagicString()
{
return this.strings.Contains(Magic);
}
public void AddString(string someText)
{
this.strings.Add(someText);
}
public void AddMagicString()
{
this.strings.Add(Magic);
}
public IEnumerator<string> GetEnumerator()
{
return this.strings.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
}
public static class MyCollectionAssertionExtensions
{
public static AndConstraint<StringCollectionAssertions> ContainMagic(this StringCollectionAssertions assertions)
{
Execute.Assertion
.ForCondition(assertions.Subject.As<MyType>().ContainsMagicString())
.FailWith("No, there's no magic");
return new AndConstraint<StringCollectionAssertions>(assertions);
}
}
@dennisdoomen
Copy link

Or make it an extension method on of the built-in assertion classes?

@philippdolder
Copy link
Author

I'm not sure if the ExtensionMethodApproach.cs is how you meant it?
That's the only way I came up with.

And this has a big drawback.
while this works perfectly

var testee = new MyType();
testee.AddMagicString();

testee.Should().ContainMagic();

this is unwanted, but possible

new List<string>().Should().ContainMagic();

and leads to NullReferenceException

@dennisdoomen
Copy link

Then your original proposal is probably the best. Overload resolution with generic constraint is just too limited right now. That's the reason why I had to introduce a ShouldBeEquivalentTo rather than a Should().BeEquivalentTo

@philippdolder
Copy link
Author

ok, thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment