DEV Community

Nalla Senthilnathan
Nalla Senthilnathan

Posted on • Updated on

Angular Testing - A Simple Strategy

In this post I share a unit and integration testing strategy that makes it simple writing test cases for Angular SPAs. Conventionally, unit testing an Angular SPA involves unit testing all the components, services, etc. In the suggested strategy the navigation flow of the various view states of an SPA is considered as a set of state transitions where each transition has one action method. If all the business rules for a given transition is encapsulated in this one action method then unit testing involves testing just one method for a given transition. Each state transition is unit and integration tested. So in this strategy we achieve "Transitions Coverage" instead of "Code Coverage".

Consider a UI requirement like - when a route /products is accessed the application should display a list of products for the signed in user who has the eligible role to view the list of products.

Conventionally, Angular code for the above requirements is distributed in several Angular Typescript artifacts like:

  1. A ProductsComponent calls a ProductsService and displays the list of products.
  2. An AuthenticationGuard ensures that the user is signed in and
  3. A RoleGuard ensures that the user has the required role to view the list of products.

So writing unit tests to cover these multiple components to assert the requirements gets involved and time consuming.

The simple strategy suggests first writing the requirements as a set of state transitions.

The state transition for the requirements stated above can be written like:

HOME > products > processPoducts() > productsSuccess > PRODUCTS

where HOME and PRODUCTS are the initial and final states of the application, products and productsSuccess are the pre and post events and processPoducts() is the action that performs the transition. If we encapsulate all the business rules like getting the products list from the service, checking whether the user is signed in etc. in this one function - processProducts() then this function can then be unit tested easily. In this approach the ProductsComponent just receives the data and displays it which can then be easily tested in the e2e integration testing. Interestingly, it turns out that, in this strategy when all the transitions are written up for an SPA, unit testing all the process functions boils down to unit testing just one function called doTransition() with various input data for each transition! This feature enables writing unit tests fairly quickly.

The implementation details of the above technique for a small SPA with three views can be found in GitHub. Unit tests for all the state transitions are in just one file test-state-transitions.spec.ts (Note that the only method tested is doTransition() in all the test cases for the whole SPA).

Running ng test for the above SPA gives an output like:

Unit Test Results

The command ng e2e can be run to test whether the Angular components like HomeComponent, ProductsComponent etc. display the right data. The e2e script can be found in cypress-integration-tests.spec.ts. Running ng e2e gives:

Integration Test Results

The above screenshots show that the state transitions provide clear guidelines to writing both unit and integration test cases.

Error conditions are not discussed in the above example but can be easily included by adding additional transitions like:

HOME > products > processPoducts() > productsError > PRODUCTSERROR

Conclusions:

The suggested strategy for unit testing Angular SPAs is shown to have the following benefits:

  1. Simpler to understand and implement test cases compared to the conventional approach.
  2. Faster to implement test scripts compared to that in the conventional approach.

Top comments (0)