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

Matching Lists with Iterables #186

Open
tomaine2002 opened this issue Jan 9, 2019 · 4 comments
Open

Matching Lists with Iterables #186

tomaine2002 opened this issue Jan 9, 2019 · 4 comments
Labels
P2 A bug or feature request we're likely to work on S2

Comments

@tomaine2002
Copy link

The DeepCollectionEquality class used for argument matching intentionally does not consider a List equivalent to a non-list Iterable, even if they have the same elements in the same order.

Generally, the test isn't interested in whether the system under test passes a List or some other Iterable. Instead, the test just wants to verify the Iterable has the expected elements in the expected order.

The simple way to specify the expected iterable argument is to use a List with the expected values, in the expected order. However, if the system under test passes an Iterable that is not a list, the stub will never match.

@natebosch
Copy link
Member

Can you give more specifics on the usage you'd like to enable here? Is it something like when(mock.someCall([1,2,3])) ?

Can you try when(mock.someCall(argThat(orderedEquals([1,2,3]))))?

@tomaine2002
Copy link
Author

you give more specifics on the usage you'd like to enable here? Is it something like when(mock.someCall([1,2,3])) ?

Yes, that's the way I'd like to set up the stub. It seems to me this should match for any Iterable with the elements 1, 2, 3 in that order.

Can you try when(mock.someCall(argThat(orderedEquals([1,2,3]))))?

That works as expected. Thanks for this suggestion. It seems unintuitive to me that when(mock.someCall([1,2,3])) and when(mock.someCall(argThat(orderedEquals([1,2,3])))) do not have the same meaning.

I'd prefer the simpler when(mock.someCall([1,2,3])) if it had the same effect as when(mock.someCall(argThat(orderedEquals([1,2,3]))))

The current behavior will likely lead to tests that are too tight. For example, if the system under test passes a List for an Iterable argument and the stub matches with a List like when(mock.someCall([1,2,3])) everything initially works. However, if someone later changes the system under test to use a non-list Iterable (e.g. replacing someCall(list) with someCall(list.where(...))), then the test will start to fail because the stub doesn't match, even if the system under test is correct.

@srawlins
Copy link
Member

srawlins commented Jan 9, 2019

I actually don't like that test's equals treats Iterables specially, so that a Set can be considered equal to a List, as long as their elements are the same.

However, I think it is more important that mockito match test's functionality rather than the functionality that mockito's extension of DeepCollectionEquality provides, which asserts that a List is matched with a List.

Changing this behavior would be a breaking change. Not sure how much internal code it would affect; maybe a lot.

@srawlins
Copy link
Member

srawlins commented Jan 9, 2019

Here's a little demo:

import 'package:mockito/mockito.dart';
import 'package:test/test.dart';

class A {
  String m1(Iterable i) => null;
}

class MockA extends Mock implements A {}

void main() {
  test('list and iterable equality stuff', () {
    var a = MockA();
    var i1 = [2, 4, 6].map((e) => e / 2);

    when(a.m1([1, 2, 3]))
        .thenReturn('argmatcher [1,2,3]         matches an Iterable that spits out 1,2,3');
    print(a.m1(i1) ??
        'argmatcher [1,2,3]       does NOT match   an Iterable that spits out 1,2,3');

    when(a.m1(argThat(orderedEquals([1, 2, 3])))).thenReturn(
        'argmatcher orderedEquals([1,2,3]) matches an Iterable that spits out 1,2,3');
    print(a.m1(i1));

    when(a.m1(argThat(equals([1, 2, 3])))).thenReturn(
        'argmatcher equals([1,2,3])        matches an Iterable that spits out 1,2,3');
    print(a.m1(i1));

    expect([1, 2, 3], equals(i1));
    expect(i1, equals([1, 2, 3]));
    print(equals([1, 2, 3]).matches(i1, {}));
  });
}
$ dart b.dart 
00:00 +0: list and iterable equality stuff
argmatcher [1,2,3]       does NOT match   an Iterable that spits out 1,2,3
argmatcher orderedEquals([1,2,3]) matches an Iterable that spits out 1,2,3
argmatcher equals([1,2,3])        matches an Iterable that spits out 1,2,3
true
00:00 +1: All tests passed!

@srawlins srawlins added P2 A bug or feature request we're likely to work on S2 labels Jul 16, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P2 A bug or feature request we're likely to work on S2
Projects
None yet
Development

No branches or pull requests

3 participants