Running end to end tests (Rest APIs)
Unit and integration tests are important to verify that isolated and integrated software modules are behaving as expected. Nevertheless, end to end tests (sometimes called system tests) are also important, because they allow to test the system as a whole, as seen for the end user. End to end tests are different from unit and integration tests because the SuT (Software under Test) is deployed in the same environment as in production.
To execute an end to end test in ElasTest, the SuT have to be declared explicitly. Then, any TJob can be associated to that SuT. In this way, the SuT can be managed independently the number of TJob executed against it.
Here we will run our JUnit5 Rest Test provided by default in ElasTest, which makes use of a rest application as a SuT and has a single test that is responsible for making a GET request to that Sut. This test has been developed in Java using JUnit5:
RestAppTest class
public class RestAppTest extends ElasTestBase {
@Test
public void rootServiceTest() {
String appHost = System.getenv("ET_SUT_HOST");
if (appHost == null) {
appHost = "localhost";
}
RestTemplate client = new RestTemplate();
String url = "http://" + appHost + ":8080/";
logger.info("Send GET request to {}", url);
String result = client.getForObject(url, String.class);
assertThat(result).isEqualTo("Hello World!");
}
}
ET_SUT_HOST
variable will be the IP of our SuT. ElasTest will automatically inject the right value (Know more about Environment Variables)
In addition, as can be seen in the example, this test class extends a class called ElasTestBase which is responsible for printing logs at the beginning and end of each test. These two logs have a specific structure and are used by ElasTest to filter the logs and metrics corresponding to each test
, as well as knowing its start and end date. We explain this in more detail here
ElasTestBase class
public class ElasTestBase {
protected static final Logger logger = LoggerFactory.getLogger(ElasTestBase.class);
@BeforeEach
public void logStart(TestInfo testInfo) {
logger.info("##### Start test: " + testInfo.getTestMethod().get().getName());
}
@AfterEach
public void logEnd(TestInfo testInfo) {
logger.info("##### Finish test: " + testInfo.getTestMethod().get().getName());
}
}
Running the "JUnit5 Rest Test" TJob
To Run "JUnit5 Rest Test" TJob you only need follow these steps:
1. Access your ElasTest dashboard
2. Get into "Rest API" project
3. Run the 'JUnit5 Rest Test' TJob
4. Execution screen is open automatically
Our TJob will start running: you will see the test information and log.
Once the test is finished you will see the test results and log. Eventually the test should end succesfully.
IMPORTANT: ElasTest make use of xml results file to get all the test results information.
You can click on the Test Suite to display it and see each of the Test Cases. You can also click on one of them to navigate to the information section of this Test Case, where you can see their logs filtered thanks to the two traces of logs that the class ElasTestBase prints at the beginning and end of each test and that we have commented above. There's only one in this TJob, so we'll navigate to this one (rootServiceTest):
You can click too on the View In LogAnalyzer
button for navigate to Log Analyzer Tool and view the execution logs:
Or you can click on the View Case In LogAnalyzer
button view the specific test execution logs:
Creating a "JUnit5 Rest Test" TJob yourself
If you want to create the TJob yourself, you only need follow these steps:
1. Access your ElasTest dashboard
2. Create a New Project
The Projects serve to organize the TJobs related to each other. You can create a new Project by clicking on the button with the same name. You only need to indicate the name of the project and then click on SAVE button:
Immediately you will be redirected to the project page:
3. Create a SuT
There are several ways to deploy a Sut in ElasTest, but they can be grouped in two ways:
Deployed by Elastest
: your software is packaged as Docker container/s. It can be a single Docker image or a docker-compose.- With Commands Container: Your SuT is packaged as a Docker image. You must write the Commands Container Image and the commands that will run like the docker image CMD.
- With Docker Image: Your SuT is packaged as a Docker image. ElasTest will pull it from DockerHub and run it as the
Dockerfile
states. - With Docker Compose: Your SuT is declared as a docker-compose. ElasTest will pull all the necessary images from DockerHub and run them as the field
Docker Compose
.
Deployed outside ElasTest
: your software is already deployed somewhere.- No instrumentation: No monitoring traces sent to ElasTest.
- Instrumented by ElasTest: Elastest will be responsible for accessing your Sut to send monitoring traces.
- Manual Instrumentation: If you want to manually send its logs and metrics to ElasTest.
- Use External Elasticsearch: if you use your own Elasticsearch to save the monitoring traces and you want ElasTest to access it to retrieve them.
You can read Software under Test for more detailed information about Sut.
In our case, we will need to insert the following data for create the SuT of "JUnit5 Rest Test" TJob:
- SuT Name: can be called as you want, but we will call it
Rest App
- With Commands Container / With Docker Image / With Docker Compose:
With Docker Image
- Docker Image: image of the SuT (
elastest/demo-rest-java-test-sut
) - Wait for http port: which port of the SuT should ElasTest wait to be available before starting the TJob (
8080
)
4. Create a new TJob
When a TJob is created, the minimum information that you have to provide is the following:
- TJob Name: name of the TJob
- Select a SuT: If your TJob make use of a Software under Test. In this case, none.
- Environment docker image: the docker image that will host your test. This docker images should contain a client to download your code from your repository hosting service. For example, if your tests are hosted in GitHub and implemented in a Maven project with Java, you need to include a git client, Maven and the Java Development Kit (JDK) in the image.
- Commands: these are the bash commands to be executed to download the code from a repository and to execute the tests. The specific commands depends on the source code repository type and the technology.
In our case, we will need to insert the following data for the TJob "JUnit5 Rest Test":
- TJob Name: can be called as you want, but we will call it
JUnit5 Rest Test
-
Test Results Path:
/demo-projects/rest/junit5-rest-test/target/surefire-reports
. This is the complete path where the xml reports of the execution in the container will be saved. We explain this in more detail here. -
Select a SuT: already created SuT to be tested through to the TJob (
Rest App
) -
Environment docker image:
elastest/test-etm-alpinegitjava
(image that contains Git, Maven and Java). - Commands:
git clone https://github.com/elastest/demo-projects; cd /demo-projects/rest/junit5-rest-test; mvn -B test;
By clicking on SAVE the TJob will be saved and you will be redirected to the project page again, where you will be able to execute the TJob.
5. Run the TJob from the Project's page
In this example, when the TJob is executed, the following steps are performed:
- SuT is executed starting the docker container
elastest/demo-rest-java-test-sut
- ElasTest waits until container has a http service available in port
8080
- When service is ready, the test container
elastest/test-etm-alpinegitjava
is started and specified commands are executed on it. - The test implemented in
/demo-projects/rest/junit5-rest-test
maven project is executed. This test makes a http request to a Rest endpoint in the SuT and verifies that current result is the expected one. - When the test container finishes, ElasTest stops the SuT and TJob containers.
More examples
The following examples, also offered by default in ElasTest, are implemented with different technologies:
RestAppTest class
public class RestAppTest extends ElasTestBase {
@Test
public void rootServiceTest() {
String appHost = System.getenv("ET_SUT_HOST");
if (appHost == null) {
appHost = "localhost";
}
RestTemplate client = new RestTemplate();
String url = "http://" + appHost + ":8080/";
logger.info("Send GET request to {}", url);
String result = client.getForObject(url, String.class);
assertEquals("Hello World!", result);
}
}
ElasTestBase class
public class ElasTestBase {
protected static final Logger logger = LoggerFactory.getLogger(ElasTestBase.class);
@Rule
public TestName name = new TestName();
@Before
public void logStart() {
logger.info("##### Start test: " + name.getMethodName());
}
@After
public void logEnd() {
logger.info("##### Finish test: " + name.getMethodName());
}
}
TJob Configuration
- TJob Name: can be called as you want, but we will call it
JUnit4 Rest Test
- Test Results Path:
/demo-projects/rest/junit4-rest-test/target/surefire-reports
- Select a SuT:
Rest App
- Environment docker image:
elastest/test-etm-alpinegitjava
- Commands:
git clone https://github.com/elastest/demo-projects; cd /demo-projects/rest/junit4-rest-test; mvn -B test;
TestRest class
import unittest
import os
import sys
import xmlrunner
import ElasTestBase
import requests
class TestRest(ElasTestBase.ElasTestBase):
def test_root_service(self):
sutUrl = ElasTestBase.sutUrl
print 'Send GET request to ' + sutUrl
response = requests.get(sutUrl)
self.assertEqual(response.content, 'Hello World!')
if __name__ == '__main__':
file_path = './testresults'
if not os.path.exists(file_path):
os.makedirs(file_path)
file_name = file_path + '/results.xml'
with open(file_name, 'wb') as output:
unittest.main(
testRunner=xmlrunner.XMLTestRunner(output=output),
failfast=False, buffer=False, catchbreak=False)
ElasTestBase class
import unittest
import os
sutUrl = None
class ElasTestBase(unittest.TestCase):
def setUp(self):
global sutUrl
testName = self._testMethodName
print '##### Start test: ' + testName
sutIp = '172.17.0.3'
if('ET_SUT_HOST' in os.environ):
sutIp = os.environ['ET_SUT_HOST']
sutUrl = 'http://' + sutIp + ':8080'
def tearDown(self):
testName = self._testMethodName
print '##### Finish test: ' + testName
TJob Configuration
- TJob Name: can be called as you want, but we will call it
Python Rest Test
- Test Results Path:
/demo-projects/rest/python-rest-test/testresults
- Select a SuT:
Rest App
- Environment docker image:
elastest/test-etm-alpinegitpython
(Alpine image with Git and Python)
- Commands:
git clone https://github.com/elastest/demo-projects; cd /demo-projects/rest/python-rest-test; python RestTest.py;
rest-test-spec.js
var request = require('request');
config = require('./elastest-conf.js');
describe('Rest Test', function() {
it('Root Service Test', function(done) {
console.log('Send GET request to ' + config.sutUrl);
request.get(config.sutUrl, function(error, response, body) {
expect(body).toEqual('Hello World!');
done();
});
});
});
elastest-conf.js
var jasmineReporters = require('jasmine-reporters');
jasmine.getEnv().addReporter(
new jasmineReporters.JUnitXmlReporter({
consolidateAll: true,
savePath: 'testresults',
// this will produce distinct xml files for each capability
filePrefix: 'xml-report',
}),
);
var reporterCurrentSpec = {
specStarted: function(result) {
console.log('##### Start test: ' + result.description);
},
specDone: function(result) {
console.log('##### Finish test: ' + result.description);
},
};
jasmine.getEnv().addReporter(reporterCurrentSpec);
module.exports = {
sutUrl: process.env.ET_SUT_HOST ? 'http://' + process.env.ET_SUT_HOST + ':8080' : 'http://172.17.0.3:8080',
};
TJob Configuration
- TJob Name: can be called as you want, but we will call it
Jasmine Rest Test
- Test Results Path:
/demo-projects/rest/jasmine-rest-test/testresults
- Select a SuT:
Rest App
- Environment docker image:
elastest/test-etm-alpinegitnode
(Alpine image with Git, Node, and necessary libraries like jasmine)
- Commands:
npm install --save request; git clone https://github.com/elastest/demo-projects; cd /demo-projects/rest/jasmine-rest-test; jasmine;
root-service-test.feature
Feature: Test a Sut
Scenario: Navigate to url and obtain 200 response
Given url appUrl
When method get
Then status 200
Scenario: Navigate to url and obtain 500 response
Given url appUrl
When method get
Then status 500
RestAppTest class
@RunWith(Karate.class)
public class RestAppTest {
}
karate-config.js
function() {
// Log start and finish every scenario
karate.log('##### Start test:',karate.info.scenarioName);
karate.configure("afterScenario",function(){
karate.log('##### Finish test:',karate.info.scenarioName);
});
var host = java.lang.System.getenv('ET_SUT_HOST');
if(!host) {
host = "localhost"
}
var url = "http://" + host + ":8080";
var config = {
appUrl: url
};
return config;
}
TJob Configuration
- TJob Name: can be called as you want, but we will call it
Karate Rest Test
- Test Results Path:
/demo-projects/rest/karate-rest-test/target/surefire-reports
- Select a SuT:
Rest App
- Environment docker image:
elastest/test-etm-alpinegitjava
- Commands:
git clone https://github.com/elastest/demo-projects; cd /demo-projects/rest/karate-rest-test; mvn -B test;