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

typed() doesn't work well with named parameters #106

Closed
robertoscaramuzzi opened this issue Mar 20, 2018 · 2 comments
Closed

typed() doesn't work well with named parameters #106

robertoscaramuzzi opened this issue Mar 20, 2018 · 2 comments

Comments

@robertoscaramuzzi
Copy link

robertoscaramuzzi commented Mar 20, 2018

In order to transition to strong mode, we have been converting our when() and verify() calls from
any and captureAny to typed(any) and typed(captureAny)

However this doesn't work well with named parameters where

when(... foo: any) becomes when(... foo: typed(any, named: 'foo'))

Why does typed need to know the name of the parameter?
And the tests will break when the name of the parameter is refactored, which runs counter to one of the main advantages of Mockito compared to other mocking frameworks.

@srawlins
Copy link
Member

In order to transition to strong mode, we have been converting our when() and verify() calls from
any and captureAny to typed(any) and typed(captureAny)

However this doesn't work well with named parameters where

when(... foo: any) becomes when(... foo: typed(any, named: 'foo'))

This is all true ☹️

Why does typed need to know the name of the parameter?

You can look at the implementation to see the reasons the named parameter is required. In brief, we can look at an example:

when(obj.fn(
      typed(any), typed(any),
      foo: typed(any, named: 'foo'), bar: typed(any: named('bar')));

// works like:

when     // Declare that a "when" statement is in progress, and return a callable object.
(        // Call the object returned by "when".
obj.fn(  // Call noSuchMethod from Mock.
    // Aha, it looks like we are passing an argument matcher to the call. Store the "any"
    // value as the first argument to "fn".
    typed(any),
    // Aha, it looks like we are passing *another* argument matcher to the call. Store
    // the "any" value as the *second* argument to "fn".
    typed(any),
    foo:
        // It looks like we are passing *another* argument matcher to the call, but the
        // order between this, and the "bar" call is not guaranteed. Dart might execute
        //  "foo:" first or "bar:" first. When "typed" is being executed, it of course
        // cannot see that it's return value is being assigned to a named argument of a
        // function, named "foo".
        typed(any, named: 'foo')
    bar:
        // Same as above. Not sure which named parameter this is being assigned to, so
        // must read the "named" argument of "typed".
        typed(any, named: 'bar')
));

And the tests will break when the name of the parameter is refactored, which runs counter to one of the main advantages of Mockito compared to other mocking frameworks.

Also unfortunate, but in most cases the tests will throw reliably:

when(obj.fn(foo: typed(any))); // throws ArgumentError
when(obj.fn(typed(any, named: 'something'))); // throws ArgumentError
when(obj.fn(newFoo: typed(any, named: 'foo'))); // throws ArgumentError

The one case where Mockito will surprise and fail you is swapping named parameter names:

when(obj.fn(foo: typed(any, named: 'bar'), bar: typed(any, named: 'foo')));

Poor Mockito is sort of helpless here. You stored an argument named "foo" and one named "bar", and then sure enough, noSuchMethod received an Invocation with a named argument, "foo", and another, "bar". ☹️.

Now that the build package is stabilizing and support is theoretically growing (CC @matanlurey), we're planning a code-generating release of Mockito, after Mockito 3, which will be able to analyze code, and generate mock methods in a smarter fashion than noSuchMethod.

@matanlurey
Copy link
Contributor

Closed as WAI for now.

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

No branches or pull requests

3 participants