-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[NP] add HTTP resources testing strategies #54908
[NP] add HTTP resources testing strategies #54908
Conversation
Pinging @elastic/kibana-platform (Team:Platform) |
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 is a very good presentation of existing testing tools, their pros/cons, and their preferred usage, with associated route testing exemples.
I'm just wondering if the type of tests presentation should really belongs in the HTTP Routes
subsection or we should add a higher level section with them. Else I'm afraid we are going to introduce a lot of redundancy / repetition when describing how to test the other functional sections (so/es...), as the type of tests are quite similar.
Some rewordings/rephrasing comments: (please ignore some or all)
It depends on the content of the other sections. 🤔 |
I have the feeling the other sections will have a quite similar layout regarding the type of tests, so I think having a 'tool presentation' section before the guidelines on how to test the different part of the plugins would make sense yes. Would like to have the others' opinion before having you restructure all this though. @rudolf @joshdover @eliperelman WDYT ? |
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.
LGTM. Would be nice to have a second reviewer though.
I think the "TestUtils" section is the closest to addressing #51150:
Your "TestUtils" example shows how to do (2) - (4) (or in the case of path parameters, it's obvious how to do it yourself), but it doesn't cover (1). In your example it's easy to test the controller logic that catches the import {dashboardModel} from './dashboardModel';
router.get(
{
path: '/myPlugin/dashboard/{id}',
validate: {
params: schema.object({
id: schema.string({ maxLength: 100 }),
}),
},
},
async (context, request, response) => {
try {
const dashboard = await dashboardModel.find(request.params.id);
return response.ok({ body: JSON.stringify(dashboard) });
} catch(error) {
if (error instanceof SavedObjectNotFoundError) {
return response.badRequest({ body: error.message })
}
}
}
); // src/plugins/my_plugin/server/integration_tests/formatter.test.ts
jest.mock('../dashboardModel');
import { dashboardModel } from '../dashboardModel';
import * as kbnTestServer from 'src/test_utils/kbn_server';
dashboardModel.find.mockRejectedValueOnce(new SavedObjectNotFoundError());
describe('myPlugin', () => {
describe('GET /myPlugin/dashboard', () => {
let root: ReturnType<typeof kbnTestServer.createRoot>;
beforeAll(async () => {
root = kbnTestServer.createRoot();
await root.setup();
await root.start();
}, 30000);
afterAll(async () => await root.shutdown());
it('returns 404 if dashboard not found', async () => {
const response = await kbnTestServer.request
.get(root, '/myPlugin/dashboard/10')
.expect(404);
expect(response.body).toHaveProperty('message');
});
});
}); Something else that could be useful would be to mock Core services or other plugins to test your controller logic, again I haven't tried this... // src/plugins/my_plugin/server/integration_tests/formatter.test.ts
import * as kbnTestServer from 'src/test_utils/kbn_server';
describe('myPlugin', () => {
describe('GET /myPlugin/dashboard', () => {
let root: ReturnType<typeof kbnTestServer.createRoot>;
let start;
beforeAll(async () => {
root = kbnTestServer.createRoot();
await root.setup();
start = await root.start();
start.plugins.data = dataPluginMock;
}, 30000);
afterAll(async () => await root.shutdown());
it('returns 404 if data plugin cannot locate index pattern', async () => {
start.plugins.data.getIndexPattern.mockRejectedValueOnce(new NotFoundError());
const response = await kbnTestServer.request
.get(root, '/myPlugin/myroute/10')
.expect(404);
expect(response.body).toHaveProperty('message');
});
});
}); |
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 think this document will be a really useful reference!
|
||
#### HTTP Routes | ||
##### TestUtils |
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.
Although it's a form of integration testing, I wonder if we shouldn't move this out of the "Integration tests" section into it's own section called "Controller testing" or "controller integration testing". ITO the testing pyramid we would have from bottom to top: unit testing, controller testing, integration testing. Because it's a very lightweight type of integration test we should encourage more "controller testing" than fullstack integration tests.
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.
TestUtils
is not limited by controller testing
. For example, you can use it to test any data kept in memory by your plugin (registry pattern).
Wouldn't it be enough to test it similarly to // plugin
try{
await model.do(savedObjectsClient)
} catch(error) {
if (SavedObjectsErrorHelpers.isNotFoundError(error)) {
return response.badRequest({ body: error.message })
}
}
// test
it('allows SavedObjects "Not found" error to bubble up', async () => {
jest.assertion(1);
try{
await model.do()
} catch(error){
expect(SavedObjectsErrorHelpers.isNotFoundError(error)).toBe(true);
}
}); Regarding the two options that you proposed:
WDYT? |
c1d2934
to
dd3922c
Compare
expect(sanitizer.sanitize).toHaveBeenCalledWith('aaa'); | ||
}); | ||
afterAll(async () => await root.shutdown()); | ||
it('returns BadRequest if Sanitizer throws MisformedTextError', 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.
❤️
I like the example you added 👍
I agree, it's better to create an abstraction between your controller and dependencies rather than directly calling Core/Plugin API's from the controller. |
* add HTTP resources testing strategies * address comments * add error message test and update error test * Apply suggestions from code review Co-Authored-By: Rudolf Meijering <[email protected]> * add controller testing example Co-authored-by: Rudolf Meijering <[email protected]>
* add HTTP resources testing strategies * address comments * add error message test and update error test * Apply suggestions from code review Co-Authored-By: Rudolf Meijering <[email protected]> * add controller testing example Co-authored-by: Rudolf Meijering <[email protected]> Co-authored-by: Rudolf Meijering <[email protected]>
* master: (21 commits) [SIEM][Detection Engine] critical blocker updates to latest ECS version [Monitoring] Fix inaccuracies in logstash pipeline listing metrics (elastic#55868) Resetting errors and removing duplicates (elastic#56054) Add flag to opt out from sub url tracking (elastic#55672) [SIEM][Detection Engine] critical bug, fixes duplicate tags [ML] Anomaly Detection: Fix persist/restore of refreshInterval in globalState. (elastic#56113) [ML] Single Metric Viewer: Fix annnotations refresh. (elastic#56107) adapt ObjectToConfigAdapter.getFlattenedPaths to consider arrays as final values (elastic#56105) Add Appender.receiveAllLevels option to fix LegacyAppender (elastic#55752) [ML] Process delimited files like semi-structured text (elastic#56038) Charts plugin (combining ui/color_maps and EuiUtils) (elastic#55469) fix tutorial documentation (elastic#55996) [ML] Fix persist/restore of time/refreshInterval in data visualizer. (elastic#56122) [Index Management] Fix errors with validation (elastic#56072) [Index Management] Add try/catch when parsing index filter from URI (elastic#56051) [NP] add HTTP resources testing strategies (elastic#54908) [ML] Single Metric Viewer: Fix brush update on short recent timespans. (elastic#56125) [Uptime] Add timeout for slow process to skipped functional tests (elastic#56065) refactor (elastic#56121) Move tests in dashboard into appropriate folders (elastic#55304) ...
Summary
Part of #53135
Documents integration- & unit-testing strategies for HTTP resources
[skip-ci]