When beginning an API program it is important to form a strategy around testing.
Agreeing on the approach and tooling to be used for API testing is key both in terms of confidence in the APIs being developed and reducing maintenance costs of the API catalogue.
This article will cover some of the principles behind a sound test strategy but will not be a deep dive into technical details, there are references at the bottom of the article where the technical details are discussed in more depth.
The main goal of any test strategy is to agree on how to automate both integration and [if necessary] unit level test harness in order to:
The key here is automation - irrespective of various techniques employed by QA teams, humans are not capable of executing complex test scenarios as consistently, frequently and as quickly as machines can.
These test harnesses can be reused to build monitoring checks for health checking purposes, e.g. "make a reservation to hotel room then cancel the booking" repeated every 2 minutes.
Monitoring Strategies will be the subject of a separate article.
There are a number of key questions to ask when formulating your strategy in order make sure it reflects your current level of testing and Agile maturity.
Arguably the most important testing for an API layer is integration testing. These tests simulate an API client sending certain request combinations and assert response received from the API.
For Apigee integration testing, the objective is to test client to Apigee + Apigee to Target + Target to backend systems integration and all integrations in middle, e.g. to other 3rd party APIs.
The objective for integration testing is to build a test harness to execute each and every policy - perhaps with many requests running multiple scenarios. We need to use our judgment and trace tool to understand what percentage of policies are covered by test scenarios.
Apigee does not have any builtin tooling to report test coverage.
Mocking Target systems may help automate testing and is recommended in following scenarios:
Building mocks for targets systems should be seen as a long term strategy and the cost of keeping these mocks up to date and how much time is invested in building the mocks should be considered as part of the testing strategy.
Integration tests generally assert following points:
Integration testing using low-level code that only developers can read, understand and run is good but its effects are limited.
BDD introduces a business centric vocabulary (e.g. gherkin) that is specifically built to ensure better understandability and participation by business audience.
By writing specifications in plain text with vocabulary that is common to the entire organisation, we are documenting the scenarios, expected outcomes and our understanding of what the software should do all in one go.
This will then improve communication between teams - technical and non-technical.
Compare the below test scripts and assess the intended audience profile, usefulness and their reach within the organisation:
describe('Check weather in cities', function() { async.each(weatherData.simpleWeatherArray() , function(cityData, callback) { it('you should be able to get forecast weather for ' + cityData.name + ' from this API Proxy.', function(done) { var options = { url: cityData.url, //'https://testmyapi-test.apigee.net/weathergrunt/apigee/forecastrss?w=2502265', headers: { 'User-Agent': 'request' } } request(options, function (error, response, body) { expect(body).to.contain(cityData.name) //Sunnyvale, Madrid assert.equal(cityData.responseCode, response.statusCode) done() }) }) callback(); }); }); |
Scenario: Check whether in cities Given I set "User-Agent" header to request When I GET /weathergrunt/apigee/forecastrss?w=2502265 Then response body should contain "Sunnyvale, Madrid" And response code should be 200 |
Scenario: Check whether in cities Given I am looking for information about Sunnyvalue, Madrid When I make a request for weather information Then response should be for "Sunnyvale, Madrid" And response should be valid |
The further down the list you progress the more 'human readable' the test cases become and the less technical knowledge is required to write the test but additional 'wiring' will be required to get the test to run.
When assessing how far to go down the BDD route a few questions worth asking are
Whatever approach you decide on needs to maximise the skills of the team you have and also minimise communication barriers between technical and non technical members of the team form the Product Owner through to developers and testers.
If everyone has a clear, common understanding of what the team is trying to deliver this will clearly improve the quality of what is produce and will also minimise the need for rework and likelihood of misunderstanding of requirements during development.
With an Apigee implementation, when we talk about unit testing we are mostly referring to "unit testing" custom code written in javascript, java, python, node.js as extension policy.
Scenarios where unit testing is useful are:
Unit testing has nice-to-have advantages over integration testing:
Any test strategy needs to balance the amount if Unit vs Integration testing performed. Overlap between the two is inefficient and requires test maintenance in two places so consider carefully what you're looking to test and what is the most efficient way of testing.
It is important to analyse what level of testing will be performed in each Apigee environment as a bundle is promoted on the path to production.
In general 'moving testing to the left' would be the suggested approach where as much testing as possible is done as early as possible with testing moving to more smoke testing in the further right environments i.e. those closer to production.
This can be used as a suggested starting point:
Environment | Testing | Notes |
DEV | Unit testing Integration testing | Target mocked if possible in order to simulate every condition easily and quickly |
INTG | Unit testing Integration testing | Target pointing to an instance of non-prod API Using different dataset than DEV environment Some tests might be disabled e.g. target 500 handling |
Other non-prod environments | Unit testing Smoke testing | Mostly testing to ensure successful deployment and configuration Very simple assertions |
PROD | Smoke testing | Mostly testing to ensure successful deployment and configuration |
The main objective is to find the capacity limit point of the whole system: the uppermost limit in terms of load in which, system behaves within the acceptable range, that is in terms of response latency, and number of successful transactions. Then use this point to do capacity planning and to define SLAs.
Up until we hit the capacity limit point, average response times stay stable and relative increase in response times are very small. When we hit this point
We may not see all of those at the same time. For example, it is possible to see an increase in error rate without degradation in latency.
The way we usually conduct the performance testing:
The readings that we are interested in are TPS values and response times in a classic REST api testing. If we are testing on private cloud, then hardware readings from each node is also important, e.g. the classic mem, cpu, IO trio.
If we are testing Apigee proxy performance only - independent of performance characteristics of target systems, we can choose to:
This important if you don't want to get isolated readings from Apigee infrastructure ONLY.
Forming a test strategy that reflects the skills of your team, the complexity of your APIs and the maturity of your Agile process should be a key part of planning your API Program.
If the strategy is too lightweight then quality will suffer and your APIs will become costly to maintain as too much time will have to be spent on bug fixing and manual regression testing.
If the strategy is over-engineered then the cost of testing may outweigh the benefits and more time can be spent setting up testing than developing APIs.
The testing strategy should ensure that the Product Owner, Developers and Testers have a clear idea of the functionality being developed and the test coverage required.
http://community.apigee.com/articles/2935/agile-assurance-advice-for-starting-the-agile-jour.html
https://community.apigee.com/articles/3964/unit-testing-javascript-code-with-mocha-sinon-and.html
https://community.apigee.com/articles/4188/unit-testing-code-coverage.html
https://community.apigee.com/articles/2685/apickli-rest-api-integration-testing-framework-bas.html