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

Mocking final classes? #635

Closed
slaci opened this issue May 16, 2023 · 6 comments
Closed

Mocking final classes? #635

slaci opened this issue May 16, 2023 · 6 comments

Comments

@slaci
Copy link

slaci commented May 16, 2023

Hello,

Dart 3 introduced some class modifiers, like final. A class marked with final cannot be extended and mocks are basically created by extending a class. So currently I get the following error when trying to mock a final class:

Error: The class 'ClassName' can't be implemented outside of its library because it's a final class.

In java there is a package called mockito-inline which somehow solves mocking final classes (don't know how).

So my question:
Do anyone see a way to make it possible to mock final classes in dart mockito?

How I ran into this: A plugin author marked some of the plugin's classes final which I previously mocked for tests. So I guess its not a good idea to mark plugin classes final, right?

@srawlins
Copy link
Member

We cannot support mocking a final class.

Do anyone see a way to make it possible to mock final classes in dart mockito?

How I ran into this: A plugin author marked some of the plugin's classes final which I previously mocked for tests. So I guess its not a good idea to mark plugin classes final, right?

Questions like this are better asked at a user forum like StackOverflow or Discord.

@781flyingdutchman
Copy link

For those coming across this: consider using the 'interface' modifier instead of 'final' for classes that are visible to package users. It does allow Mockito to mock it, and it still prevents the class from being extended (which is usually the bigger concern for package developers).

@gdutpxz
Copy link

gdutpxz commented May 22, 2023

For those coming across this: consider using the 'interface' modifier instead of 'final' for classes that are visible to p

but most sense we use mock for a 3rd lib...

@slaci
Copy link
Author

slaci commented May 23, 2023

Yes that's the same issue @gdutpxz as I encountered. As @781flyingdutchman suggested replacing final by interface should achieve the same goal (at least we came to this conclusion).

The main problem is that most plugin developers don't really think about these user written tests. Most plugins are not mockable by default because they use global variables/functions. But now even those plugins won't be mockable which use final classes, if the devs don't know about this issue. Well final classes are much worse, because global functions can be wrapped, but final classes... well they could be wrapped too, but meh.

Now in mockito 5.4.1's changelog there is a line:

Fail to generate mocks of sealed/base/final classes.

Not sure what does that mean yet, but mockito can't do anything more about this sadly.

@yanok
Copy link
Contributor

yanok commented May 23, 2023

Yes, you can't mock final classes (or base or sealed).

The thing is, if you own this class, it's your call, you can either remove final, or split it into interface that can be mocked and final implementation. (you can even make your interface @visibleForTesting if you want to emphasize it's not there for production use).

If you don't own this class, it's a bit trickier. You can create your wrapper class that contains the class you want to mock and just passes all requests to it. Then you can mock this wrapper class. Of course, for this to be useful, you would have to rewrite all your code to use your wrapper, instead of using the original class directly. Unfortunately that's the only way, if original class' authors are not willing to make a mockable interface.

@yanok yanok closed this as completed May 23, 2023
@slaci
Copy link
Author

slaci commented May 23, 2023

Just to summarize, there are 2 options for this:

  • Ask the plugin author to replace final by interface or just remove final. Check class modifiers doc.
  • If the above is not an option, then the only way is to wrap the plugin's class in a wrapper class which you can mock, and use that everywhere.

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

5 participants