-
Notifications
You must be signed in to change notification settings - Fork 1.7k
avoid casts on calls to mock methods #27027
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
Comments
Hey @leafpetersen ... I just thought of an interesting complication here. Continuing my example above, we'd have to know to disallow this kind of override: class DerivedMockMonster extends MockMonster {
// override error: int -> int is not a subtype of Object -> int from MockMonster
int damage(int hp) => hp.isEven ? 0 : 1000;
} ... because that would tighten up the parameter type. If we say nSM "implements" all abstract methods and widens parameter types to Object, we could do it, but it disallows overrides later on. Implementation wise, we'd want to track the induced members explicitly in the element model as synthetic ones. So a bit tricky. But conceptually I'm not sure how I feel about it. Is it too restrictive? Using nSM becomes kind of dangerous as it will silently "widen" your abstract members. Perhaps a better pattern is to alter the mock package API: verify(mock).damage(argThat(isPositive)).thenReturn(100);
verify(mock).damageFromClosure(argThat(isFunction)).thenReturn(200); By wrapping the mock object it's possible to accept different signatures. |
My initial (somewhat tentative) thinking was that this wouldn't be the default behavior, but something you opted into via an annotation or syntax at the NSM declaration site. So a standard NSM codegens with the right signature, but if you put the annotation there ( |
For some context, the class DerivedMockMonster extends MockMonster {
// override error: int -> int is not a subtype of Object -> int from MockMonster
int damage(int hp) => hp.isEven ? 0 : 1000;
} is an example of mixing faking and mocking, which is a highly discouraged pattern. The damage override will take precedence on any stubbing, which can lead to hard to debug tests. The recommended way would be to set common behavior in the setUp(() {
when(mockMonster.damage(any)).thenAnswer((int hp) => hp.isEven ? 0: 1000);
}); For the mocking use-case, I don't believe preventing narrowing again is an issue. |
@thso @leafpetersen do y'all like the opt-in annotation idea? It would only need to appear on the nSM, so derived classes don't need to worry about it: class Mock {
// ...
@SomeAnnotationHere()
noSuchMethod(Invocation invocation) { /* ... */ }
} Any naming ideas? Since it's not going to occur very frequently something that feels more explanatory might be preferable to a really short name, e.g. Alternatively we could make it the default, and let the covariant overrides feature be used for narrowing, if that's ever needed. It sounds like it isn't needed for mockito, and I think they are one of the main users of nSM. |
Yes, I'm in favor. Perhaps |
I'm in favor of making it optional, I don't think it's a behavior one would expect in other circumstances. |
sounds good to me! fyi, this is kind of blocked for the same reason as: ... but as soon as we get that resolved (one way or the other) I can take a look |
sent out patch for 25578 so picking this one back up |
actually ... going to wait for that patch to land so I can build on it. The CL for it is https://codereview.chromium.org/2336503003/ |
Thanks @jmesserly! Would you have some vague ETA on this? |
thanks for the ping. I need to think it over again to see if there's a nice way of implementing it. Even after the 25578 fix, it didn't seem clear how we can fit it in nicely. But in the meantime I've been trying to (slowly) get things into a more hackable state. Stay tuned. |
@thso This is proving a bit complex to implement, I'd like to get a sense of how much this is a blocker for things we need, and how much this is a nice to have (and if the former, how urgently). |
ping, are we still interested in a feature like this? I think it would be challenging to have to implement it in both CFE and Analyzer at this point. Assuming stale, but let me know if we should reopen |
For example:
We'll want to allow
mock.damage
to avoid the cast toint
. This is safe because when using nSM to implement abstract methods, the method is conceptually implemented by a method that forwards to nSM, and that method can widen the argument types to Object.The text was updated successfully, but these errors were encountered: