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

"type 'Null' is not a subtype of type" on getter #608

Open
AdrienAudouard opened this issue Feb 15, 2023 · 14 comments
Open

"type 'Null' is not a subtype of type" on getter #608

AdrienAudouard opened this issue Feb 15, 2023 · 14 comments
Assignees
Labels
P2 A bug or feature request we're likely to work on status-cant-reproduce status-needs-info

Comments

@AdrienAudouard
Copy link

AdrienAudouard commented Feb 15, 2023

Hello,

I'm trying to generate a mock for a class witch contains a getter, the source code of the class is:

class AppContext {
...
  AppLocalizations get l10n => AppLocalizations.of(navigatorMaterialAppKey.currentContext!);
}

Then I generate a mock of the class with mockito and with the following code:

@GenerateNiceMocks([
  MockSpec<AppContext>(),
])

When I run the tests I have the following error: type 'Null' is not a subtype of type 'AppLocalizations', it look like in the generated code, the mock code of the getter is not generated.

Can you help me please ? 🙏

The generated code:

/// A class which mocks [AppContext].
///
/// See the documentation for Mockito's code generation for more information.
class MockAppContext extends _i1.Mock implements _i81.AppContext {
  @override
  _i28.GlobalKey<_i28.NavigatorState> get navigatorMainPageKey =>
      (super.noSuchMethod(
        Invocation.getter(#navigatorMainPageKey),
        returnValue: _FakeGlobalKey_34<_i28.NavigatorState>(
          this,
          Invocation.getter(#navigatorMainPageKey),
        ),
        returnValueForMissingStub: _FakeGlobalKey_34<_i28.NavigatorState>(
          this,
          Invocation.getter(#navigatorMainPageKey),
        ),
      ) as _i28.GlobalKey<_i28.NavigatorState>);
  @override
  _i28.GlobalKey<_i28.NavigatorState> get navigatorVaultKey =>
      (super.noSuchMethod(
        Invocation.getter(#navigatorVaultKey),
        returnValue: _FakeGlobalKey_34<_i28.NavigatorState>(
          this,
          Invocation.getter(#navigatorVaultKey),
        ),
        returnValueForMissingStub: _FakeGlobalKey_34<_i28.NavigatorState>(
          this,
          Invocation.getter(#navigatorVaultKey),
        ),
      ) as _i28.GlobalKey<_i28.NavigatorState>);
  @override
  _i28.GlobalKey<_i28.NavigatorState> get navigatorMaterialAppKey =>
      (super.noSuchMethod(
        Invocation.getter(#navigatorMaterialAppKey),
        returnValue: _FakeGlobalKey_34<_i28.NavigatorState>(
          this,
          Invocation.getter(#navigatorMaterialAppKey),
        ),
        returnValueForMissingStub: _FakeGlobalKey_34<_i28.NavigatorState>(
          this,
          Invocation.getter(#navigatorMaterialAppKey),
        ),
      ) as _i28.GlobalKey<_i28.NavigatorState>);
}
@srawlins
Copy link
Member

Questions like this are best asked on a user forum like StackOverflow, with more eyes to look at the question.

@yanok
Copy link
Contributor

yanok commented Apr 28, 2023

Yep, it seems we don't override getters with non-nullable return type, but we have to. Thanks for reporting. I plan to re-work the codegen for Dart3 support significantly, I think this bug will be fixed too.

@yanok yanok self-assigned this Jun 1, 2023
@yanok yanok added type-bug Incorrect behavior (everything from a crash to more subtle misbehavior) P1 A high priority bug; for example, a single project is unusable or has many test failures labels Jun 1, 2023
@yanok
Copy link
Contributor

yanok commented Jun 1, 2023

Yep, it seems we don't override getters with non-nullable return type, but we have to. Thanks for reporting. I plan to re-work the codegen for Dart3 support significantly, I think this bug will be fixed too.

The rewrite didn't fly, so I guess we just have to do the overrides.

@AdrienAudouard
Copy link
Author

Okay, thanks for your reply, good luck 😄

@yanok yanok added status-needs-info P2 A bug or feature request we're likely to work on and removed P1 A high priority bug; for example, a single project is unusable or has many test failures labels Jun 1, 2023
@yanok
Copy link
Contributor

yanok commented Jun 1, 2023

Actually I can't reproduce it. And the line that does the getter override is there since 2020.

So, your generated code does indeed look wrong, but I don't understand how that could happen.

  • Which version of Mockito do you use?
  • What is the package:analyzer version?
  • Which language version do you use for your project?
  • Do you use mixed mode, with some sources being at one language version, while others at another one? Especially with regard to nullability feature?

@yanok yanok added status-cant-reproduce and removed type-bug Incorrect behavior (everything from a crash to more subtle misbehavior) labels Jun 30, 2023
@yanok
Copy link
Contributor

yanok commented Jun 30, 2023

@AdrienAudouard ping, I can't fix it if I can't reproduce it :)

@yanok yanok closed this as completed Aug 18, 2023
@Ahmad-Hamwi
Copy link

@yanok Hi, I have the issue and I've reproduced it in this repo.
It's a very minimal project, please take a look. All required info is in the readme file.

@yanok
Copy link
Contributor

yanok commented Sep 4, 2023

This should be in the FAQ, I guess. You must declare variables holding mock objects to have Mock* types. In your code
here https://github.com/Ahmad-Hamwi/mockito-gen-issue/blob/5879e544b97b3c08a8176b4ffd6a914331de9a68/test/app_localizations_mockable.dart#L14

  late IAppLocalization mockAppLocalization;

MUST be

  late MockIAppLocalization mockAppLocalization;

@Ahmad-Hamwi
Copy link

If I understand OOP correctly, this shouldn't be the problem, should it? Since the runtime type will be a Mock* anyways.

But here's a screenshot after changing what you've suggested, and running the test again, the test still fails with the same error:

Screenshot 2023-09-04 at 4 04 30 PM

@yanok
Copy link
Contributor

yanok commented Sep 4, 2023

Oh, sorry, my bad. While what I said is correct and you still have to declare your mocks to have Mock types (since that's static type that matters while checking if method arguments have correct type), in your case the error indeed comes from something else. There gotta be a generated override for instance getter and it's missing in the generated code.

Thanks for the reproduction. I'll take a look a bit later.

@yanok yanok reopened this Sep 4, 2023
@Ahmad-Hamwi
Copy link

Sure no problem.
Thank you for reopening the issue. Tyt.

@yanok
Copy link
Contributor

yanok commented Sep 4, 2023

The problem with your code is AppLocalizations having InvalidType at the time of Mockito codegen running. This is because Analyzer can't find package:flutter_gen/gen_l10n/app_localizations.dart under .dart_tool/flutter_gen. I actually wonder what makes it work when it runs "for real".

@Ahmad-Hamwi
Copy link

Thank you for you insights.

So basically generated code cannot be mocked. Is this an intended behavior for mockito or is it a feature that should be worked on?

Also, can you elaborate on what you mean about "for real"? Do you mean running the test in an emulated environment such as an integration test?

@yanok
Copy link
Contributor

yanok commented Sep 6, 2023

No, we can mock generated code, though there are also possible issues, since we have to be sure other generators run before mockito, and I think there is no generic way to ensure this. Actually this might be the cause here too, I thought the problem is the "magic" import, but maybe mockito generator just runs before flutter_gen?

By "magic" import I mean that this flutter_gen package is a bit special: it allows you to refer to the generated code via package:flutter_gen/... URLs, while it's clearly not a part of package:flutter_gen itself. So there is some magic setting that allows Dart to find these generated files.

By "for real" I mean when you run the test with flutter test or whatever vs when running the mockito codegen. Since for the codegen we spawn the Analyzer manually, so maybe we are missing some settings that make these "magic" imports work, as the problem seems to be Analyzer can't resolve these imports.

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 status-cant-reproduce status-needs-info
Projects
None yet
Development

No branches or pull requests

4 participants