Yalantis
Learn how we perform unit testing of web software, which frameworks we use to write proper unit tests, and how we improve your software quality as a result.

Unit testing for web software: why it’s necessary and which frameworks to use

Share

Unit testing is part of the Extreme Programming methodology that aims at providing maximum software quality. But who does unit testing? In fact, unit testing is done by developers, not quality assurance (QA) engineers. A developer who performs unit testing can detect any code discrepancies at the early development stages. If developers test software during development, it’s much easier for the QA team to conduct further, more complex testing.

Eventually, all these testing stages contribute to higher software quality. However, software testing help is only one aspect of ensuring software quality. Learn how we ensure it at other levels by taking into account all project constraints.

In this article about software unit testing, we discuss:

  • why unit testing web applications is important 
  • best practices for proper unit testing
  • benefits of unit testing
  • structure of the unit test based on code example from a Yalantis developer who writes unit tests 
  • unit testing automation frameworks and unit test provider services

Levels of testing and why we need them

Unit testing is the first level of software testing required for any type of software. There is a standard set of tests necessary for all projects, but we also target each software system individually to define which additional tests we have to perform. For instance, for a medical e-prescription platform, we chose an enhanced testing package, as this type of software requires a particular emphasis on the security of patient data.

In this section, we take a look at unit testing along with integration, system, and acceptance testing.

1. Unit testing

What is unit testing? Put simply, unit testing is a method of testing units of code, typically individual functions, in isolation. A unit is an inseparable piece of functionality with its particular logic that can’t be split. At its core, a unit test is also code; thus, all the requirements that apply to writing good code also partially apply to writing a good unit test. In unit testing, the smaller the parts of code you test, the better the results, as testing smaller units gives you a more detailed view of your code’s behavior. Plus, tests run fast when dealing with small units. Why do unit testing? The core goal of unit testing in web development is to sustain the growth of the software project and ensure stable releases.

2. Integration testing

While automated unit tests verify the behavior of isolated parts of your code, integration testing for web applications covers interactions between different parts of your application. This is the next level of software testing, as integration testing checks if different units of the software work together correctly in real life. Integration tests validate complex scenarios, so they may require more effort and additional resources, such as databases or web servers.
Unit and integration tests are a great combination, as they ensure that every isolated unit works correctly and that multiple units work flawlessly and as expected when integrated.

3. System testing

You can move on to system testing once you’ve successfully completed integration testing. This is the first level at which you test the system as a whole. System testing checks whether all components are integrated and work correctly. For system testing, it’s crucial to create an environment similar to the real-life environment in which the system will be deployed. System testing verifies that the system meets functional, technical, and business requirements.

4. Acceptance testing

Acceptance testing is performed after unit, integration, and system testing. At this stage, the QA team tests the quality of the application by applying predefined test scenarios and test cases. The purpose of acceptance testing is to evaluate the system’s compliance with business requirements. This is the final level of testing and checks whether the system is ready for release.

In the next section, we dive into: 

  • more details about actual unit testing in software engineering
  • a unit test example for a web application
  • the structure of website unit testing
  • unit testing best practices

You may also be interested in how we conduct different security testing.

Unit tests in action

You may ask: Why unit testing? Because each small piece of code depends on other small pieces. Your web application is a bunch of small units working together; if you change one unit, something else can break as a consequence. Unit test automation tools can detect problematic parts of your code so you know where the problem is and what the correct behavior should be.

A unit testing strategy is also a crucial part of test-driven development (TDD). This approach emphasizes testing as the most important element of software development and requires you to write tests before the production code. However, TDD works best for solutions with well-defined documentation and clear business requirements. This way, a developer can have enough information to write the right test first and understand how the code should look in the end. TDD consists of three core steps: 

  • Write a failing test to define how certain functionality should behave
  • Write code that passes the test
  • Refactor the code to improve its readability and maintainability

Unit test web application: structure and operating principles

Different unit testing methods help to verify the behavior of small pieces of your application independently from other pieces of code. Typically, a unit test consists of three phases: Arrange-Act-Assert:

  • Arrange: Setting up the test for a particular piece of an application (called the system under test)
  • Act: Performing the actual testing (interacting with the system under test)
  • Assert: Observing the resulting behavior and checking whether expectations were met

If the resulting behavior is in line with expectations, the unit test passes — everything works correctly. Otherwise, it fails, indicating a problem with the system under test.
For the unit test to run properly, we follow the FIRST principle within the unit test methodology:

  • F — fast. The best unit testing is quick; otherwise, it’s not a unit test. Unit tests have to quickly check code performance without relying on dependencies such as databases or other services.
  • I — isolated. Unit tests have to run in isolation and not influence one another to provide the expected results. Developers should be able to run unit tests in any order and at any time.
  • R — repeatable. Each unit test has to provide the same result every time you run it. 
  • S — self-validating. Unit tests have to be programmed to determine whether they fail or pass so there’s no need for the developer to manually assess results. 
  • T — timely. Unit tests should be written just in time to check the code when it’s most necessary.

If the developer ensures the correct structure of the unit test and follows the FIRST principle of unit testing strategies, then the unit test will most likely provide the expected results. And even if it doesn’t, the developer will know that the reason for that is a problem in the system, not in the test.

Read also: Best practices for performing testing and quality assurance

Example of unit testing

What is the best approach to testing a website or a web application? Let’s find out from an example. See how we can apply a unit test to the following model. In the code below, we can see a clear distinction between the three phases.

it('should not contain not added colors', () => {
  //Arrange: initialize objects under test and required environment
  let rainbow = new CustomRainbow('Black', 'White');
  // Act: make actual call
  let res = rainbow.contains('Blue');
  // Assert: validate the result
  expect(res).toBe(false);
})

Best practices for unit testing

Below, we share a few best practices for conducting proper unit testing for web applications:

  • Relevance. Web unit testing should always be relevant and actually check something. If the result of the test doesn’t add any value to analyzing the system’s behavior, then the test is irrelevant.

  • Clear expectations. We should know exactly what result we expect from each unit test so we can correctly interpret the result. In case we get unexpected results, we should analyze the AAA structure of the unit test to define the issue. 

  • Maintaining code logic. Just as with regular code, the unit test should be also structured according to common rules and requirements, such as separating code into classes and methods.

Software developers with substantial experience in writing unit tests as well as other types of tests are aware of all the best practices that ensure testing goes just right. For our logistics client who wanted to transition their warehouse and transportation management system from a monolithic architecture to microservices, we also set up a proper testing environment. 

With a monolithic architecture, our client had to test the entire system even after the smallest changes. We implemented a proper continuous integration and delivery flow that helped us run tests for each commit. Thanks to this approach, we improved the source code quality and ensured the proper code management environment.

Let’s switch now to the advantages you get from software development unit testing.

Benefits of unit testing services

Now that we know how different types of testing work, let’s learn more about the benefits of unit testing. Many people believe that unit testing is a waste of time if they use automated tests. That’s not true.

For instance, if we perform only high-level tests such as UI automation tests with lots of steps to reach the final result. And if any of these steps fail, we’ll need to spend much time finding the part of the code that works incorrectly. On the other hand, if we first do low-level unit tests, it will be easier for us to point out exactly which unit and which part of that unit works incorrectly in case our high-level test fails.

But how exactly can we benefit from unit tests?

Find and fix bugs early

Unit tests are great for finding bugs before code is pushed to quality assurance specialists. They help developers debug software at the early stages. Finding and fixing bugs early with unit testing reduces the cost of debugging at later stages of development. 
Unit tests can become part of the continuous integration and delivery process. As software scales and the code base grows, unit tests run automatically. With unit tests, software engineers can easily check the location of the failure and debug code.

Easier code changes and refactoring

Refactoring is the process of changing working code without changing the way the app behaves. Unit tests can relieve headaches, as they ensure that code functions properly after refactoring. Unit tests are important with code refactoring and when the code base becomes larger as a result of software reengineering.

With unit tests, you get immediate feedback when you break code so you can refactor it safely. But as the software’s code base changes and grows, it’s important to also refactor unit tests to make sure you correctly test components.

Better understanding between developers

When developers write unexpected pieces of code, they can either mark them with comments (though often no one notices them) or can perform unit testing on them. When other developers stumble upon these seemingly strange code fragments that have tests performed on them, they understand right away that the code is there for a reason.

Provide documentation

Many software developers find that unit tests may become working documentation of their code, as unit tests demonstrate how to use a library or framework. Plus, unit tests are always up to date because they use the latest functionality (and show all possible functionality).

Is this a benefit? It is, as the documentation makes it easier for multiple developers to work together and hand over a project to other developers down the line. But this is true only if developers know how to write clear unit tests and write them regularly.

Automated unit testing tools

Developers use unit testing tools and frameworks to write unit tests quickly and easily, since most programming languages don’t support unit testing with the built-in compiler. There are different frameworks to deal with different unit testing types. We’ll provide a few examples of tools we use at Yalantis to automate JavaScript and Go code testing. Thanks to automation techniques, we managed to speed up testing for our medical PACS project. We ensured that the system could run tests in parallel and at any time. It was also critical for us to make sure that the system allowed the implementation of any code changes on all testing levels.

Jasmine

Jasmine is a behavior-driven development framework for testing JavaScript code. It’s suited for websites, Node.js projects, and anywhere else JavaScript is used. Jasmine doesn’t rely on browsers and JavaScript frameworks. It also doesn’t require a DOM (document object model).

Jasmine offers easy initial setup with assertions, spies, and mocks. It provides all you need to develop unit tests, as it comes with many basic features out of the box. And it’s easy to implement in any development methodology. Jasmine supports asynchronous testing and uses spies for implementing test doubles.

The main benefit of Jasmine is that it doesn’t depend on the browser, framework, and platform. In addition to being used for behavior-driven development (BDD), Jasmine can be used for test-driven development (TDD), one of the main Agile development techniques. TDD is about writing your test code first so it can guide your implementation.

Jest

Jest was built by Facebook and is based on Jasmine. It’s used by Instagram, Airbnb, Facebook, and many other companies. The Jest community appreciates its speed and simplicity. Jest runs tests simultaneously, so the whole test suite runs fast. It also provides the watch feature to run only tests that are affected by your changes in the editor.

The main advantage of Jest is that it works out of the box with minimal setup and configuration. It comes with an assertion library and mocking support. Tests are written in a behavior-driven development style, as with most popular testing libraries.

The combo of Mocha and Chai

Mocha is a feature-rich JavaScript testing framework that runs on Node.js and in a browser. At Yalantis, we use the Mocha testing framework with the Chai assertion library, which works well for JavaScript code used for data models, business logic, and utilities.

Mocha attracts lots of developers because of its simple and flexible modular nature. Mocha tests run serially, allowing for accurate and flexible reporting while mapping uncaught exceptions to the correct test cases.

Ginkgo

Ginkgo is an all-purpose Go testing framework. It’s used actively for unit, integration, system, acceptance, and performance testing. Ginkgo works best in combination with the Gomega library. With Ginkgo, developers can run different tests in parallel and then group them using labels. This framework can also run tests automatically if its ginkgowatch tool detects any changes in a test. Thus, you’ll always get rapid feedback during TDD.

Ginkgo requires a complicated setup, but it has great test organization and many features. Ginkgo and Gomega provide rich documentation, making them perfect for beginners. Thanks to Ginkgo’s versatile nature, many developers choose it for large projects.

Even though unit testing is considered a basic type of testing, its importance can’t be underestimated. The purpose of unit testing is to lay the foundation for quality software code that helps us ensure the best performance for our software system. It’s also critical to perform unit tests when refactoring applications or adding new functionality. At Yalantis, we conduct unit testing for each project and have lots of experience in all types of software testing. When developing your next project with us, you can be sure that your system will be thoroughly tested to achieve the highest quality.

Need quality assurance testing services?

We can help

Contact us

Rate this article

Share this article

4.9/5.0

based on 1,216 reviews