Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ContainItemsAssignableTo vs AllBeAssignableTo #1618

Closed
jnyrup opened this issue Jun 24, 2021 · 9 comments · Fixed by #1765
Closed

ContainItemsAssignableTo vs AllBeAssignableTo #1618

jnyrup opened this issue Jun 24, 2021 · 9 comments · Fixed by #1765

Comments

@jnyrup
Copy link
Member

jnyrup commented Jun 24, 2021

Description

Is there any difference between ContainItemsAssignableTo and AllBeAssignableTo?
Spending five minutes looking at them, they seem to test the same scenario.
(With the exception, that AllBeAssignableTo has special handling for IEnumerable<Type>)

In contrast to other Contain methods, ContainItemsAssignableTo expects all elements to satisfy and not just a subset.

Complete minimal example reproducing the issue

class Base { }
class Derived : Base { }

public void MyTestMethod()
{
    new[] { new Derived(), new Base() }.Should().AllBeAssignableTo<Derived>();  // fails as expected
    
    new[] { new Derived(), new Base() }.Should().ContainItemsAssignableTo<Derived>(); // <-- I would have expected this to pass
}
@dennisdoomen
Copy link
Member

You're on to something. I was expecting ContainItemsAssignableTo to verify that at least one item is assignable to T. But both the docs and implementation confirm it's doing exactly the same thing as AllBeAssignableTo. I'm not sure that's a bug or a design flaw though...

@siewers
Copy link

siewers commented Jun 28, 2021

Very interesting and a freaky occurrence :)
In our team, we just discussed this 10 minutes ago, and had to opt using an inferior .[Not]Contain(x => x is MyType) as ContainItemsAssignableTo asserts on all items, and not just whether the collection contains at least one item assignable to T.

We are now discussing whether to implement a new assertion .[Not]ContainItemOfType<T>, but maybe it's something on the FluentAssertions roadmap already?

@dennisdoomen dennisdoomen added this to the 6.0 milestone Jun 28, 2021
@dennisdoomen
Copy link
Member

I think we should fix the behavior for the next 6.0 beta.

@siewers
Copy link

siewers commented Jun 28, 2021

I think it might need some additional assertion options. If you want to assert the collection only contains a single instance of type T, how would that be done?
Something like .ContainSingleOfType<T>(...) might be useful? However, I haven't thought through this.

@jnyrup
Copy link
Member Author

jnyrup commented Jun 29, 2021

I think it might need some additional assertion options. If you want to assert the collection only contains a single instance of type T, how would that be done?
Something like .ContainSingleOfType<T>(...) might be useful? However, I haven't thought through this.

If ContainItemsAssignableTo<T>() returns a AndWhichConstraint<..., IEnumerable<T>>, one could write it as

subject.Should().ContainItemsAssignableTo<T>()
    .Which.Should().ContainSingle();

@siewers
Copy link

siewers commented Jun 29, 2021

Ah, yes, that is an option, although I find it a little less fluent :)
I would probably prefer something that resembles a sentence like:

"the collection should contain a single item of type T "

and not:

"the collection should only contain items of type T of which there should only be one"

;)

@siewers
Copy link

siewers commented Jun 29, 2021

Scratch my comment about .ContainSingleOfType<T>, that is already supported today:

collection.Should().ContainSingle().Which.Should().BeOfType<T>();

@eNeRGy164
Copy link
Contributor

eNeRGy164 commented Jun 29, 2021

These are different assertions.

subject.Should().ContainItemsAssignableTo<T>()
    .Which.Should().ContainSingle();

Collection can contain multiple types, but exactly 1 is matching the specified type

collection.Should().ContainSingle()
    .Which.Should().BeOfType<T>();

Collection can only contain a single item, and it should match the specified type

@siewers
Copy link

siewers commented Jun 29, 2021

@eNeRGy164 Yes, you are right of course :)
I still think that scenario reads a bit messy.
I would never talk like that, and reading it as

"subject should contain items assignable to type T, of which there should be only one"

versus

"subject should contain only one item of type T"

, I know which one I would prefer.

However, I am not sure how to express this fluently, without breaking existing convention.

subject.Should().Contain().AtMost(1).OfType<T>();
subject.Should().Contain().AtLeast(1).OfType<T>();

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

Successfully merging a pull request may close this issue.

4 participants