Skip to content

Integration and Unit testing

Nevil edited this page Nov 17, 2022 · 7 revisions

What is integration testing?

Integration testing is a kind of testing in which software modules are logically integrated and tested as a group. A typical software project consists of multiple software modules coded by different programmers. This level of testing aims to find bugs in the interactions of these software modules when they are integrated.

The approach we took

One of the main challenges we faced while adding integration testing was the interdependencies of microservices. The solution to this was running the test cases inside a docker container, this way we eliminate the dependency issues and provides a clean environment each time the test is run.
The testing framework we choose is JEST. It works out of the box and it primarily focuses on simplicity.
SuperTest was used for the HTTP assertions. It extends another library called superagent, a JavaScript HTTP client for Node.js and the browser. We can use SuperTest as a standalone library or with our testing framework Jest.

File structure

Inside the test, we have a folder for each controller. Each has 3 files. For example, the account controller has accountData.js,account.spec.js, and responseSchema.js.

.
├── account
│ ├── accountData.js
│ ├── account.spec.js
│ └── responseSchema.js
├── commonTests.js
...

CommonTests.js

Almost all of our APIs require authentications so commonTests acts like a helper for all the test cases. When called it creates and logs in with an account returning the user details including the token. Since all API calls need some common headers like X-auth-token or Connection, we can set these as the default header for all API calls made with superTest, this was implemented with the help of this package.

Test file(**.spec.js)

The actual test cases are in the account.spec.js file.
describe breaks your test suite into components. Depending on your test strategy, you might have a describe for each function in your class, each module of your plugin, or each user-facing piece of functionality.
it is where you perform individual tests. You should be able to describe each test in a little sentence, such as "/user/v1/account /create". You shouldn't be able to subdivide tests further-- if you feel like you need to, use describe instead.

describe("/user/v1/account", function () {
  it("/create", async () => {});
  it("/login", async () => {});
  it("/verifyMentor", async () => {});
});

CURD operations using superTest

await request.post('/user/v1/account/login').send({
	email: email,
	password: password,
})

Where request is defined as const request = defaults(supertest(baseURL)) //supertest hits the HTTP server (your app).
This is an example of the post method where the body is passed via the .send(). Other HTTP methods can be used instead of .post, headers can be set using .set.
For more examples and options refer superagent.

Data file(**Data.js)

Any seeding-related function should be inside the data file. It helps us to insert required data into the DB directly. This is useful since we will be running our tests in a sandboxed environment.

Schema file(responseSchema.js)

Validating the response of the test cases is an important aspect of integration testing. Instead of matching only the status code received, we can do deep assertion checks. Jest has expect out of the box. It gives you access to several "matchers" that let you validate different things.
But we can go further and validate the JSON schema we received, this way we can minimize the chances of missing keys and their data type. We use this package to validate our response schema. JSON Schema is nothing but a contract for your JSON document that defines the expected data types and format of each field in the response. JSON schema generator is a handy tool to generate the JSON schema. So in responseSchema.js, we store all the expected response JSON schema which we use to validate the actual response we get from the test.

To run the integration testing:

Use the command to run the integration testing

npm run test:integration

JEST config

Since we're already using jest for our unit testing we can specify the config file that we want to use with integration testing. This can be done using with the help of Jest CLI Options.
jest --verbose ./integration-test --config=integrationJest.config.js --runInBand this is the actual command hidden in npm run
Here the --verbose helps us to display individual test results with the test suite hierarchy.
./integration-test is the path to the test files and it looks for files ending in .spec.js or .test.js by default.
--config=integrationJest.config.js is the path to a Jest config file specifying how to find and execute tests.
--runInBand to run all tests serially in the current process.

setupFilesAfterEnv

In the jest config file, we can have setupFilesAfterEnv which is nothing but a list of paths to modules that run some code to configure or set up the testing framework before each test file in the suite is executed. Here we use it to connect to our database.

CircleCi integration

To run all the tests we can use CircleCi.CircleCI is a continuous integration and continuous delivery platform that can be used to implement DevOps practices. Assuming that you've already connected GitHub with circleci, we can go into the config file located in ../.circleci/config.yml.By default circleci uses docker containers, since we will be using docker containers to set up the server it better to use a Linux VM, this is to reduce the performance issues that we will face because of running docker inside docker.

...
  build:
    machine: #Linux machine instead of docker environment
      image: ubuntu-2004:202111-01
      docker_layer_caching: true
...

when the docker_layer_caching is set to true circleci will try to cache the docker images, making the test get completed faster.Click here to read more. To make the test results available in circleci we can use jest-junit and add

      - store_test_results:
          path: ./dev-ops/report

to the circleci config file to make the test results available after the VM is torn down.

Tools used:


What is unit testing?

Unit testing may be a software development process in which the minor testable parts of an application, called units, are individually and independently scrutinized for correct operation. This testing methodology is completed during the development process by the software developers and sometimes QA staff. The objective of unit testing is to isolate written code to test and determine if it works as intended.