-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Support constructor parameters for spying on abstract classes #685
Comments
I've thought about some variant of this feature for a while, so here's some feedback. It'd be nice if we have some concrete use cases to study. In my own experience, I have mostly managed to avoid needing this feature by spying non-static abstract class. For example, if the abstract class I'm spying on needs two constructor parameters, I do this: public class FooTest {
@Spy private MockAbstractFoo foo;
private final Bar bar = ...;
private Baz baz() {...}
abstract class MockAbstractFoo extends AbstractFoo {
MockAbstractFoo() {
super(bar, baz());
}
}
} Fwiw:
|
I forgot to mention that it is possible with today's API to pass different constructor parameters, through MockSettings. Like the following: class MockFooFactory {
private final Bar bar;
private final Baz baz;
MockFooFactory(Bar bar, Baz baz) {...}
public AbstractFoo create() {
return Mockito.mock(MockFoo.class, withSettings()
.useConstructor().outerInstance(this).defaultAnswer(CALLS_READ_METHODS));
}
abstract class MockFoo extends AbstractFoo {
MockFoo() {
super(bar, baz);
}
}
} Then just call it with: new MockFooFactory(bar, baz).create(); Again, this is static type safe and IDE friendly compared to reflection-based API. The Mockito.spy(outerInstance, MockFoo.class); |
To quote the requirement: ''' We already support spying on abstract classes by allowing parameterless constructor. However, there is no support for constructor parameters. This has been asked about long time ago. Mockito API is not robust enough if it supports mocking with constructor but not when one has any constructor parameters. ''' This patch enhances the MockSettings#useConstrctor() method and adds optional ellipsis arguments that are passed to the constructor. The patch streamlines the creation of mocks via constructors to a single flow, where using a no-arg constructor or an enclosing class are just private cases of this flow, and don't require their own special treatment.
I think that overloading I've coded this approach in PR #935. Feedback is more than welcome! |
To quote the requirement: ''' We already support spying on abstract classes by allowing parameterless constructor. However, there is no support for constructor parameters. This has been asked about long time ago. Mockito API is not robust enough if it supports mocking with constructor but not when one has any constructor parameters. ''' This patch enhances the MockSettings#useConstrctor() method and adds optional ellipsis arguments that are passed to the constructor. The patch streamlines the creation of mocks via constructors to a single flow, where using a no-arg constructor or an enclosing class are just private cases of this flow, and don't require their own special treatment.
To quote the requirement: ''' We already support spying on abstract classes by allowing parameterless constructor. However, there is no support for constructor parameters. This has been asked about long time ago. Mockito API is not robust enough if it supports mocking with constructor but not when one has any constructor parameters. ''' This patch enhances the MockSettings#useConstrctor() method and adds optional ellipsis arguments that are passed to the constructor. The patch streamlines the creation of mocks via constructors to a single flow, where using a no-arg constructor or an enclosing class are just private cases of this flow, and don't require their own special treatment.
Agreed that Personally, I'm not convinced that the dynamic type support is worth the effort. It seems to be a slippery slope toward defeating Java static type safety, which reminds me of the ancient JMock vs. EasyMock comparison where the former relied on type-less reflection while the latter is static type safe. If Java doesn't allow you to call That said, if you do decide to add this feature, there are a few implementation caveats that we need to be careful about:
|
To quote the requirement: ''' We already support spying on abstract classes by allowing parameterless constructor. However, there is no support for constructor parameters. This has been asked about long time ago. Mockito API is not robust enough if it supports mocking with constructor but not when one has any constructor parameters. ''' This patch enhances the MockSettings#useConstrctor() method and adds optional ellipsis arguments that are passed to the constructor. The patch streamlines the creation of mocks via constructors to a single flow, where using a no-arg constructor or an enclosing class are just private cases of this flow, and don't require their own special treatment.
To quote the requirement: ''' We already support spying on abstract classes by allowing parameterless constructor. However, there is no support for constructor parameters. This has been asked about long time ago. Mockito API is not robust enough if it supports mocking with constructor but not when one has any constructor parameters. ''' This patch enhances the MockSettings#useConstrctor() method and adds optional ellipsis arguments that are passed to the constructor. The patch streamlines the creation of mocks via constructors to a single flow, where using a no-arg constructor or an enclosing class are just private cases of this flow, and don't require their own special treatment.
To quote the requirement: ''' We already support spying on abstract classes by allowing parameterless constructor. However, there is no support for constructor parameters. This has been asked about long time ago. Mockito API is not robust enough if it supports mocking with constructor but not when one has any constructor parameters. ''' This patch enhances the MockSettings#useConstrctor() method and adds optional ellipsis arguments that are passed to the constructor. The patch streamlines the creation of mocks via constructors to a single flow, where using a no-arg constructor or an enclosing class are just private cases of this flow, and don't require their own special treatment.
To quote the requirement: ''' We already support spying on abstract classes by allowing parameterless constructor. However, there is no support for constructor parameters. This has been asked about long time ago. Mockito API is not robust enough if it supports mocking with constructor but not when one has any constructor parameters. ''' This patch enhances the MockSettings#useConstrctor() method and adds optional ellipsis arguments that are passed to the constructor. The patch streamlines the creation of mocks via constructors to a single flow, where using a no-arg constructor or an enclosing class are just private cases of this flow, and don't require their own special treatment.
To quote the requirement: ''' We already support spying on abstract classes by allowing parameterless constructor. However, there is no support for constructor parameters. This has been asked about long time ago. Mockito API is not robust enough if it supports mocking with constructor but not when one has any constructor parameters. ''' This patch enhances the MockSettings#useConstrctor() method and adds optional ellipsis arguments that are passed to the constructor. The patch streamlines the creation of mocks via constructors to a single flow, where using a no-arg constructor or an enclosing class are just private cases of this flow, and don't require their own special treatment.
I happened to need to dig up the history of @SPY AbstractClass in #106. And I found that all my concerns against constructor-args were already stated in that thread. And it was clear that @szczepiq is fine with the trade-off. So, while I disagree with the design decision, my apologies for repeating myself over again. :) |
To quote the requirement: ''' We already support spying on abstract classes by allowing parameterless constructor. However, there is no support for constructor parameters. This has been asked about long time ago. Mockito API is not robust enough if it supports mocking with constructor but not when one has any constructor parameters. ''' This patch enhances the MockSettings#useConstrctor() method and adds optional ellipsis arguments that are passed to the constructor. The patch streamlines the creation of mocks via constructors to a single flow, where using a no-arg constructor or an enclosing class are just private cases of this flow, and don't require their own special treatment.
To quote the requirement: ''' We already support spying on abstract classes by allowing parameterless constructor. However, there is no support for constructor parameters. This has been asked about long time ago. Mockito API is not robust enough if it supports mocking with constructor but not when one has any constructor parameters. ''' This patch enhances the MockSettings#useConstrctor() method and adds optional ellipsis arguments that are passed to the constructor. The patch streamlines the creation of mocks via constructors to a single flow, where using a no-arg constructor or an enclosing class are just private cases of this flow, and don't require their own special treatment.
To quote the requirement: ''' We already support spying on abstract classes by allowing parameterless constructor. However, there is no support for constructor parameters. This has been asked about long time ago. Mockito API is not robust enough if it supports mocking with constructor but not when one has any constructor parameters. ''' This patch enhances the MockSettings#useConstrctor() method and adds optional ellipsis arguments that are passed to the constructor. The patch streamlines the creation of mocks via constructors to a single flow, where using a no-arg constructor or an enclosing class are just private cases of this flow, and don't require their own special treatment.
To quote the requirement: ''' We already support spying on abstract classes by allowing parameterless constructor. However, there is no support for constructor parameters. This has been asked about long time ago. Mockito API is not robust enough if it supports mocking with constructor but not when one has any constructor parameters. ''' This patch enhances the MockSettings#useConstrctor() method and adds optional ellipsis arguments that are passed to the constructor. The patch streamlines the creation of mocks via constructors to a single flow, where using a no-arg constructor or an enclosing class are just private cases of this flow, and don't require their own special treatment.
Support constructor parameters for spying on abstract classes Fixes #685
Thank you very much for contribution. It's really nice work! |
As the previous patch fixes issue mockito#685, there is no longer a need to reference it in the error message.
As the previous patch fixes issue mockito#685, there is no longer a need to reference it in the error message.
Nice, self-contained enhancement that makes Mockito API more robust. The implementation does not require proficiency with Mockito codebase.
Feature
We already support spying on abstract classes by allowing parameterless constructor. However, there is no support for constructor parameters. This has been asked about long time ago. Mockito API is not robust enough if it supports mocking with constructor but not when one has any constructor parameters.
Open questions
I'd say we go for option 1 because it's simpler to implement and seems more convenient (works out of the box for certain use cases). If we go for option 2 we need to inform the user what to do to resolve the problem (for example document and suggest @fluentfuture idea of creating an inner implementation)
We decided that using existing method is simpler, keeps the API small and is easy to discover.
Implementation notes
Test coverage
The text was updated successfully, but these errors were encountered: