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

How to setup calling a function on a mock with a mock as parameter (with NNBD)? #306

Closed
denniskaselow opened this issue Dec 22, 2020 · 9 comments
Assignees
Labels
P1 A high priority bug; for example, a single project is unusable or has many test failures type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)

Comments

@denniskaselow
Copy link

Using 5.0.0-nullsafety.0.

I have a class Foo and a class Bar which I want to mock for use in the class I want to test. Both classes interact with each other. Before nullsafety I could simply set this up, but I'm not sure how I am supposed to do that post-NNBD because mockito itself uses methods on the mocks that aren't mocked and I don't think I should mock stuff so mockito works.

Example:

// foobar.dart
class Foo {
  String process(Bar bar) => 'result';
}

class Bar {}

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

import 'package:foobar/foobar.dart';
import 'world_test.mocks.dart';

@GenerateMocks([
  Foo,
  Bar
], customMocks: [
  MockSpec<Foo>(as: #MockFoo2, returnNullOnMissingStub: true),
  MockSpec<Bar>(as: #MockBar2, returnNullOnMissingStub: true),
])
void main() {
  test('default mock', () {
    final foo = MockFoo();
    final bar = MockBar();
    when(foo.process(bar)).thenReturn('mockedResult');

    foo.process(bar);
  });
  test('null mock', () {
    final foo = MockFoo2();
    final bar = MockBar2();
    when(foo.process(bar)).thenReturn('mockedResult');

    foo.process(bar);
  });
}

The code fails in the foo.process(bar); line.

The resulting error of the default mock test is: NoSuchMethodError: Object has no == method accepting arguments (_)

The resulting error of the null mock test is: type 'Null' is not a subtype of type 'bool'

The important part of the stacktrace is this:

test\foobar_test.mocks.dart 62:13      MockBar2.==
package:collection/src/equality.dart 87:45          DefaultEquality.equals
package:collection/src/equality.dart 458:18         DeepCollectionEquality.equals
package:mockito/src/invocation_matcher.dart 184:18  _MatcherEquality.equals
package:collection/src/equality.dart 177:29         ListEquality.equals
package:mockito/src/invocation_matcher.dart 158:12  _InvocationMatcher.matches
package:mockito/src/mock.dart 141:27                Mock.noSuchMethod.<fn>

If I do something stupid like when(bar == bar).thenReturn(true); I'll just get a stackoverflow.

@srawlins
Copy link
Member

Great catch. This is related to #305, in which it is requested that Object.== be auto-stubbed instead of throwing.

The resulting error of the default mock test is: NoSuchMethodError: Object has no == method accepting arguments (_)

Right, so without the returnNullOnMissingStub feature, mockito has called MockBar.==, which used to return null (unless you called throwOnMissingStub) and now throws, unless you'd stubbed ==. We might be able to tiptoe around == with an is check or an identical call or something... Hopefully we can make a solution that doesn't involve new code for you to write, like a stub.

The resulting error of the null mock test is: type 'Null' is not a subtype of type 'bool'

This test uses the old behavior (returnNullOnMissingStub), in which null is returned for MockBar.==. Fixing the above case might fix this, but generally speaking, this is why the default behavior is changed; null is no longer the safe return value it once was.

@srawlins srawlins added P1 A high priority bug; for example, a single project is unusable or has many test failures type-bug Incorrect behavior (everything from a crash to more subtle misbehavior) labels Dec 23, 2020
@denniskaselow
Copy link
Author

I wouldn't call returnNullOnMissingStub the old behavior because those tests work with stable mockito. Things like ==, runtimeType and toString() never returned null. They just used the real implementation of the Mock or Object class and couldn't even be stubbed.

@denniskaselow
Copy link
Author

denniskaselow commented Dec 23, 2020

Those functions (hashcode, toString()) and operators (==) still exist on the Mock class (https://github.com/dart-lang/mockito/blob/master/lib/src/mock.dart#L155) and are maybe overridden by mistake because of #297? (and I'd not override runtimeType either) And I'd very much prefer it if that old behavior would be kept. If possible.

@srawlins
Copy link
Member

@denniskaselow You're completely right. The solution is to stop overriding any methods defined by Mock or inherited by Mock, (get hashCode, operator ==, toString(), get runtimeType).

@srawlins srawlins self-assigned this Dec 23, 2020
@srawlins
Copy link
Member

This is fixed in 5.0.0-nullsafety.1.

@radvansky-tomas
Copy link

I have still this issue in 5.0.0
'Object.==' ('bool Function(Object)') isn't a valid concrete implementation of 'CollectionReference.==' ('bool Function(dynamic)').

@srawlins
Copy link
Member

@radvansky-tomas I don't think your error is related to this issue.

@MilanObrenovic
Copy link

I still have this issue in mockito ^5.0.14

Add a stub for this method using Mockito's 'when' API, or generate the mock for MockIDatasource with 'returnNullOnMissingStub: true'.

@srawlins
Copy link
Member

@MilanObrenovic I don't see any reason why your issue is related to this one. Feel free to open a new bug with a minimal reproduction case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P1 A high priority bug; for example, a single project is unusable or has many test failures type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)
Projects
None yet
Development

No branches or pull requests

4 participants