-
Notifications
You must be signed in to change notification settings - Fork 29.7k
[flutter_tool] restructure ProjectFileInvalidator to no longer directly depend on context #45739
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
[flutter_tool] restructure ProjectFileInvalidator to no longer directly depend on context #45739
Conversation
|
FYI @christopherfujino @blasten @jmagman @zanderso For an example of removing direct context dependencies. I think the tests are a lot easier to read without a testing zone. |
| void _testProjectFileInvalidator({@required bool asyncScanning}) { | ||
| const ProjectFileInvalidator projectFileInvalidator = ProjectFileInvalidator(); | ||
| for (bool asyncScanning in <bool>[true, false]) { | ||
| test('No last compile', () async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should these tests have unique names (i.e. interpolate asyncScanning)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call, fixed
|
This is pretty cool. I agree, the test is more readable and explicit. |
zanderso
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally like the idea.
| void _testProjectFileInvalidator({@required bool asyncScanning}) { | ||
| const ProjectFileInvalidator projectFileInvalidator = ProjectFileInvalidator(); | ||
| for (bool asyncScanning in <bool>[true, false]) { | ||
| test('No last compile, asyncScanning: $asyncScanning', () async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These probably need to use testUsingContext() with a context that maps everything to a fake implementation that crashes or a Mock with no behavior to ensure that, e.g. some library called by the ProjectFileInvalidator now or in the future doesn't use default globals, like for the file system:
| context.get<FileSystem>() ?? _kLocalFs, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could wrap in a test context, possible fiddle with context a bit so that it threw if accessed at all? I think that would be preferable to creating a bunch of throwing mocks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sgtm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Giving this a shot by wrapping the existing test method ... we'll see if this works. else we could name it testWithoutContext ... or hopefully something shorter
| class ProjectFileInvalidator { | ||
| const ProjectFileInvalidator(); | ||
| ProjectFileInvalidator( | ||
| this._fileSystem, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tend to prefer named parameters when a method/constructor involves more than one parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like a good idea. Generally there is a bit more boilerplate involved if we want to use named parameters but still have private fields which is why I avoided it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fair :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still updated to use named parameters & private fields, its really a minor complaint. Plus it reads a lot better
| } | ||
|
|
||
| @isTest | ||
| void test(String description, FutureOr<void> body(), { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this wrapper be in place for all tool tests that just say test() ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we could take this opportunity to enforce some reasonable default behavior in the future if necessary, such as providing zone based throwing implementations of the real filesystem or network behavior.
| Map<String, dynamic> onPlatform, | ||
| int retry, | ||
| }) { | ||
| return runZoned(() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will the test body run in this zone?
|
|
||
| @override | ||
| T get<T>() { | ||
| throw UnsupportedError('context.get is not supported in this test.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider including $T in the exception message.
| class ProjectFileInvalidator { | ||
| const ProjectFileInvalidator(); | ||
| ProjectFileInvalidator({ | ||
| @required FileSystem fileSystem, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice!
| }); | ||
|
|
||
| testWithoutContext('Throws if accessing the Zone', () { | ||
| expect(() => fs, throwsA(isInstanceOf<UnsupportedError>())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this test just do a context.get() directly so that it isn't dependent on how the fs getter is implemented? A separate test could check that fs checks the context, but I'm not sure how valuable that test would be.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| } | ||
|
|
||
| @isTest | ||
| void testWithoutContext(String description, FutureOr<void> body(), { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs some comments about when to use and/or not use this. I think it would also be good to have a code health issue filed on github linked from here that describes what the next steps are, and maybe suggests some candidate components that could benefit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filled #47161 and added a doc comment
Description
Removes direct usage of context getters from ProjectFileInvalidator. Allows testing without testbed or context.