17

Using fluent assertions, I would like to assert that a given string contains either one of two strings:

actual.Should().Contain("oneWay").Or().Should().Contain("anotherWay"); 
// eiter value should pass the assertion.
// for example: "you may do it oneWay." should pass, but
// "you may do it thisWay." should not pass

Only if neither of the values is contained, the assertion should fail. This does NOT work (not even compile) as there is no Or() operator.

This is how I do it now:

bool isVariant1 = actual.Contains(@"oneWay");
bool isVariant2 = actual.Contains(@"anotherWay");
bool anyVariant = (isVariant1 || isVariant2);
anyVariant.Should().BeTrue("because blahblah. Actual content was: " + actual);

This is verbose, and the "because" argument must get created manually to have a meaningful output.

Is there a way to do this in a more readable manner? A solution should also apply to other fluent assertion types, like Be(), HaveCount() etc...

I am using FluentAssertions version 2.2.0.0 on .NET 3.5, if that matters.

Marcel
  • 15,039
  • 20
  • 92
  • 150

3 Answers3

14

I would make it an extension to the string assertions. Something like this:

public static void BeAnyOf(this StringAssertions assertions, string[] expectations, string because, params string[] args) {
    Execute.Assertion
           .ForCondition(expectations.Any(assertions.Subject.Contains))
           .BecauseOf(because, args)
           .FailWith("Expected {context:string} to be any of {0}{reason}", expectations);
}

You could even fork the repository and provide me with a Pull Request to make it part of the next version.

Marcel
  • 15,039
  • 20
  • 92
  • 150
Dennis Doomen
  • 8,368
  • 1
  • 32
  • 44
  • How to use this? This misses a lot of explanation! It would be great if I could create something like: `actual.Should().ContainAnyOf("oneWay", "another way");` That would be consistent with the existing way. – Roel Jul 03 '18 at 15:28
  • It allows you to call `actual.Should().BeAnyOf("oneWay", "another way");`. – Dennis Doomen Jul 05 '18 at 09:40
  • @DennisDoomen how could I implement that same method for Enums? – Damir Porobic Jul 07 '21 at 08:41
13

Should not this work?

actual.Should().BeOneOf("oneWay", "anotherWay");

Worked for me using v3.1.229.

bpforsich
  • 201
  • 3
  • 5
  • Not for me, because I do not want to assert the whole string content, but just that the actual value partially contains one of the values. – Marcel Oct 06 '14 at 06:08
2

You could make it a little more readable by writing a simple string extension:

public static class StringExt
{
    public static bool ContainsAnyOf(this string self, params string[] strings)
    {
        return strings.Any(self.Contains);
    }
}

Then you could do this:

actual.ContainsAnyOf("oneWay", "anotherWay").Should().BeTrue("because of this reason");

Unfortunately this doesn't help with the "reason" part of the message, but I think it's a little better.

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276