A Node.js Guide To Actually Doing Integration Tests

Posted on - Last Modified on

Programmers often dread integration tests, but they are an essential part of application testing. Programmers use unit tests to test a lump of code in isolation. When it is more than just a handful of codes, it is best to switch to integration test. Integration test forms a bridge between end-to-end test and unit tests.

What do programmers mean by testing?

Testing is the process of evaluating system components, to verify whether they meet the specified requirements. Missing requirements and gaps are identified during testing to see if it is contrary to the genuine or intended requirements. If integration testing is so important, how come many programmers are not doing it?

This article will teach you how to write composable and readable integration tests for API-based applications. It will throw more light on the use of JavaScript/Node.js for all code. The ideas discussed will be useful for integration tests on diverse platforms.

The different types of testing:

There are myriads of tests available for software engineers, including integration, unit, system, functional, performance, stress, acceptance, usability and so on. This article will focus on the integration test.

Logically, an integration test is an extension of a unit test. The combination of two or more units result in what is called an interface. The further combination of the interfaces forms components. Any problem that occurs at the interface level can be identified using an integration test. Successful integration testing lowers potential problems, as it makes sure performance, reliability, and function between the integrated units are working as they should.

Why you need integration and unit tests

The focus of unit tests is on a single unit of code. This is a smaller and more specific function affiliated to a bigger component. Unit tests are carried out in isolation with mocked, or stubbed external dependencies. Simply put, a pre-programmed behavior is used to replace the external dependencies, to make sure the accuracy of the test outcome is only a product of the unit under test. Units have been explained in detail here.

A unit test is one of the ways to maintain good designs and high-quality codes. The major drawback of unit testing is they do not cover inter-component interactions. This is where the  integration test becomes invaluable.

Integration test

An integration test is the direct opposite of the unit test, if you define a unit test as testing the smallest code units in isolation. Integration tests are employed to test bigger units and can sometimes cover multiple systems. The main purpose of running an integration test is to find bugs in dependencies and connections in various components like invalid cache integration, broken database schema, errors in business logic - or data flow - and the passage of incorrectly ordered or invalid arguments.

Integration testing is far more important than unit testing when you are dealing with components with lesser complicated logic; for example, lesser cyclomatic complexity. If a unit test is employed here, it will only be to make sure the code designs are good.

The disparity between a unit test and integration test lies in their functions. Whereas the appropriateness of a code is tested using a unit test, an integration test checks if the entire system is working as it should. Therefore, unit tests and integration tests can be said to be complementary in purpose. This means that for comprehensive testing, both are relevant - and you cannot claim to have completed your testing program unless both of them have been carried out.

What is the need for integration test?

  • It runs faster when placed side-by-side with an end-to-end test.

  • It is easy to integrate with daily builds.

  • It is a more reliable test for isolating failures

  • In a local environment, it is still easy to carry out integration tests.

  • System-level issues are best tracked using integration tests.

  • In a software development cycle, integration tests help catch bugs.

Who should make use of testing?

Testing is good to avoid glitches in software development. It helps developers track code breaks with few changes or modifications. The prerequisite to testing is that you need a Node.js running endpoint.

Integration test suit setup

Setting up a suit for integration test is challenging, unlike a unit test which is straightforward. This is because some components in integration testing can have dependencies that are outside the project. This includes file systems, databases, external payment services, email providers and so much more. Integration tests may occasionally rely on external services, and other times they are stubbed. Several challenges can arise when external services are needed.

  • Delay in execution: in this instance, tests happens on an external server as part of CI. Connection to such external services may be slow.

  • The test execution is fragile: external services may present one of the following challenges: unavailable, present in an invalid state or return an invalid response. These challenges may lead to false positive or false negative results.

  • The test setup is complex: for external services to qualify for testing, they have to be in the desired state.

Directions for writing integration tests

There are no strict rules for integration testing like unit tests, but there are still some rules that must be followed.

Repeatable tests

Dependencies or test order should not in any way alter the test result. In order words, irrespective of the number of times you run the test, the same result should be obtained. This may be hard to achieve if the test has to rely on an internet connection to link up with third-party services.

Testing relevant actions

Unit tests are better options if you have to test all possible cases. Integration testing is more tilted to connections among modules.

Comprehensible test

The reader has to be able to see at a glance what is under test. Assertions need not be complex and should employ helpers for superior evaluation and logging.

Easy test setup

The entire process of getting the test to the starting point should be easy to comprehend, and  simplified as much as possible.

Separate test code from production code

The production code should be direct and clean. When production code and test code get mixed, the result will be two non-connectable domains combined.

Logging

There is no value to a failed test if it is not recorded, with accurate logging. A successful test, on the other hand, will need no extra logging. A log should include API responses and requests, all database queries, and a comparison of parameters under test. These facilitate debugging to a significant level.

Helper constituents

A test is said to be comprehensive if it contains a testing framework, flow testing, database handler and means to connect backend APIs.

Flow control

Asynchronous flow remains the biggest challenge for JavaScript testing. A call back can lead to havoc in a code. Flow helpers are essential in such situations. One of the solutions to writing readable, clean, and robust asynchronous code is to use Bluebird. In fact, libraries with comparable actions can be used to achieve this purpose.

Testing framework, factory library, connecting to APIs, as well as other utilities that can help you to achieve integration testing where external dependencies are required have gotten discussed extensively here.

Extensibility and abstraction are necessary for building an operational integration test suit. Anything that takes the focus away from the test core is abstracted, and grouped into utility functions. No path in this scenario is right or wrong. It all depends on the qualities and needs of the integration test.

If you cannot run integration testing for your software for one reason or the other, there is no need to fret. You can hire an expert through Freelancer at a reasonable rate - you could even get useful tips in the process.

As a developer, you want to make sure new features of your code work alongside old ones. It is hard to achieve this without testing. An improper test can lead to the failure of the program. An integration test combined with a unit test is your best defense.

If you have new ideas about integration tests especially when dependencies are required, let us know in the comment box. Found this post useful? Go ahead and share it with your friends.

 

Posted 23 August, 2017

LucyKarinsky

Software Developer

Lucy is the Development & Programming Correspondent for Freelancer.com. She is currently based in Sydney.

Next Article

Specialist Or Generalist: Which is better for your programming career?