-
Notifications
You must be signed in to change notification settings - Fork 686
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
GEODE-10084: CliFunction should handle all throwable #7395
Conversation
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.
comment deleted
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.
The new ImportDataFunctionTest
does not test ImportDataFunction
at all. It tests CliFunction
. So move this test from ImportDataFunctionTest
to CliFunctionTest
. And change it so that instead of spying the unit under test, it creates a derived class where executeFunction()
does nothing but throw.
Then add unit tests for the new and changed functionality in ImportDataFunction
.
Oh, yeah, that's true. fixed. I don't have a test for |
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.
Thanks for moving that test to CliFunction
. It fits much better there.
These two problems remain:
- Do not spy the thing being tested.
CliFunction
is designed to be extended. So make the test create a derived class, and make itsexecuteFunction
method throw. - Write tests for
ImportDataFunction
.
Here are some test ideas.
One important change is that ImportDataFunction.executeFunction(…)
returns a result, where the old execute(…)
did not. Here are some things to test:
- If the region exists, is the result correct (status code, member name, message)?
- If the region doesn't exist, does the result correctly describe the problem (status code, member name, message)?
Here are some other things to test, to make sure they did not change:
- Does
executeFunction
invoke the callbacks from the snapshot service? - Does
executeFunction
set parallel mode according to arg 3? - Does
executeFunction
tell the snapshot service to load the snapshot with the right parameters?
Thanks for the suggestion. More tests added. I didn't change the implementation of that function, only the error handling. so that part is tested. |
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.
Thank you for adding those tests. I like that you tested them through execute()
rather than through executeFunction()
.
This problem remains, and in fact is getting worse:
- Do not spy the thing being tested.
Oh, you are right. I don't need to use spies. |
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.
Do not mock the thing being tested. CliFunction
is designed to be extended. So make the test create a derived class, and make its executeFunction
method throw.
I'm honestly astonished that the CliFunction
test passes, given that it's testing a mock. My guess is that the mock is behaving like a spy.
I did want a derived class. Here's way to do that without mocking or spying the thing being tested:
Either that or create an inner class in the test called something like Something I just noticed: It would be a good idea to assert that the result contains the exception that was thrown. Like this:
If the only reason to change |
yeah, I changed back to use a spy. |
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.
Do not mock or spy the thing being tested.
CliFunction
is designed to be extended. So make the test create a subclass, and make the subclass's executeFunction
method throw. See below (or my previous comment) for an example of how to do this.
It would be a good idea to assert that the result contains the exception that was thrown by the subclass.
Here's a test that does all of those things. Notice that it tests CliFunction
's error handling' without mocking or spying the thing being tested, and without altering an existing implementation subclass in order to test the CliFunction
:
@Test
public void executeShouldSendCliFunctionResultIfExecuteFunctionThrowsError() {
Error errorThrownByExecuteFunction = new InternalGemFireError("test");
CliFunction<Object[]> function = new CliFunction<Object[]>() {
@Override
public CliFunctionResult executeFunction(FunctionContext<Object[]> context) {
throw errorThrownByExecuteFunction;
}
};
function.execute(context);
ArgumentCaptor<CliFunctionResult> captor = ArgumentCaptor.forClass(CliFunctionResult.class);
verify(resultSender).lastResult(captor.capture());
CliFunctionResult result = captor.getValue();
assertThat(result)
.isNotNull();
assertThat(result.getResultObject())
.isSameAs(errorThrownByExecuteFunction);
}
If the only reason to change ImportDataFunction
was to use it to test CliFunction
, then those changes are not necessary. (Though it would be a shame to throw those new tests away.)
I understand it as a theory. But in this particular case, isn't |
The purpose of mocks (and, in very rare cases, spies) is to make it easier for the test to control and observe the collaborators of the thing you're testing. It's true that code I offered does create some noise. To make it more readable, move the noise into a helper method, and name the helper method to make its purpose in the test clear. So the body could do something like this:
|
I don't think I agree in this particular case, but I will quit making my case. |
* Update ImportDataFunction to extend CliFunction (cherry picked from commit 41e7a17)
* Update ImportDataFunction to extend CliFunction
No description provided.