Blog / Development / Angular

Angular Marble Testing: A Brief Introduction

  • Rating — 5 (2 voices)
  • by Mykola on December 07, 2018
  • Read —
    4-5 minutes
marble testing

Working with Angular implies a wide use of reactive programming, that is, programming with asynchronous data streams. Angular components often operate with several observable streams that have overlapping sequences of values and errors. Testing such scenarios using common methods is often complicated. RxJS Marble Testing is much more helpful in these cases.

In this article, we’ll try to explain what is marble testing and how it works.

  1. What is marble testing?
  2. ‘Jasmine-marbles’ library
  3. Example

What is marble testing?

Marble testing allows you to test asynchronous RxJS code synchronously and step-by-step with the help of RxJS TestScheduler test utility and using virtual time steps.

There are also marble diagrams which demonstrate what is happening with a particular operation in the observable stream.

angular marble testing

ASCII marble diagrams are an alternative way to describe the observable stream. For instance, ASCII diagram a–bc—d–#–| corresponds to the marble diagram on the image above.

A marble diagram in TestScheduler is a string of characters that represents events which occur during the virtual time. Time progresses through ‘frames’. The first character represents a zero ‘frame’ or the beginning of time.

  • “-” — 10 ‘frames’ of time passing
  • “|” — the successful completion of the observable stream. Corresponds to the complete() method.
  • “#” — the error completion of the observable stream. Corresponds to the error() method.
  • “a” (or any other alphanumeric character) — a value emitted by the observable stream. Corresponds to the next() method.
  • “()” — a grouping of several events that should occur synchronously in one ‘frame’. Allows you to group the emitted value with the end of stream or an error.
  • “^” — a subscription point (only for hot observables). It’s a ‘zero frame’ for the observable, so each frame before ^ will be negative. Negative time may be needed during ‘ReplaySubjects’ testing.
  • “!” —  the end of a subscription point.

ASCII marble diagrams are used to create so-called hot and cold observable streams, which, in their turn, are used as mock-ups in test-waiting methods. Let’s discuss this next.

Jasmine-marbles library

‘Jasmine’ provides the ‘npm’ package ‘jasmine-marbles’. It is a library for `TestScheduler` that significantly simplifies marble testing. This package is not included in the Angular CLI test suite, so it must be installed separately: ‘$ npm install jasmine-marbles –save-dev’

‘Jasmine-marbles’ provides two methods for creating observables out of marble diagrams:

  • ‘cold (marbles: string, values ?: object, errors ?: any)’ – the subscription starts when the test begins
  • ‘hot (marbles: string, values ?: object, errors ?: any)’ – it’s already “running” when the test begins; the subscription starts with the “^” character.

ASCII marble diagram is passed to both methods as the first argument. The second argument is an optional object matching the characters in the diagram and their values. If this object is absent, the created observable will be emitting the characters from the diagram. If there is an error in the stream, it will be passed as the third argument.

For instance, ‘cold(‘–a–b–|’, {a: 10, b: ‘hello’})’ will create a cold observable stream that will emit value 10 at 30ms, value ‘hello’ at 60ms and will end at 90ms.

Thanks to the work of the test scheduler, the test is synchronous (`fakeAsync ()` is not used).

Example

Let’s take a look at a common example – a counter component.  

We have the following requirements to the component:

  1. The component must have two buttons (‘Up’ and ‘Down’) and a counter.
  2. The counter should start at 0.
  3. Clicking the ‘Up’ button should add 1 to the counter; clicking the ‘Down’ button should subtract 1 from the counter.

Now, let’s create a component test considering the above requirements:

marble testing code

Next, we need to describe the logic behind the way the component works with the observable stream using marble diagrams:

  1. Stream of events after pressing the ‘Up’ button
  2. Stream of events after pressing the ‘Down’ button.
  3. The resulting stream.

Now, based on the marble diagrams, let’s create the observable streams using the ‘cold ()’ method from the `jasmine-marbles` library. We need this to verify whether the resulting observable stream of the counter corresponds to the observable streams of click events on the ‘Up’ and ‘Down’ buttons.

After that, we can implement a component code that will successfully pass the tests.

import { Component } from '@angular/core';
import { merge, Observable, Subject } from 'rxjs';
import { mapTo, scan, startWith } from 'rxjs/operators';

@Component({
 selector: 'app-counter',
 template: `
   <button (click)="up$.next()">Up</button>
   <button (click)="down$.next()">Down</button>
   <div class="counter">{{counter$ | async}}</div>
 `,
})
export class CounterComponent {
 counter$: Observable<number>;
 up$ = new Subject();
 down$ = new Subject();

 constructor() {
   const {up$, down$} = this;
   this.counter$ = this.getCounter({up$, down$});
 }

 getCounter({up$, down$}) {
   return merge(
     up$.pipe(mapTo(1)),
     down$.pipe(mapTo(-1))
   ).pipe(
     startWith(0),
     scan((x, y) => x + y)
   )
 }
}

To receive a whole code from this article, fill out the form below and click Send Download Link button.

Enter your name and email to download the file.

Conclusion

As mentioned, the described methodology is indeed very effective and it’s the best option for testing asynchronous RxJS code. It will help you easily test even the most complex networks of observable streams in various Angular components of the application.

Looking for professional app developers for your next project?

Mykola is a web developer at GBKSOFT. His professional experience includes 10+ years of software development with a focus on Angular and React in recent years. Mykola’s hobby is to learn rare features and share his knowledge with the tech community.


Leave a comment
Close

Leave a Reply


Similar Blog Articles

Development

Pros and Cons of JavaScript Full Stack Development

Web development projects usually require making numerous tech decisions and the most crucial of them are: what technologies to use for the frontend (i.e. client-side) and backend (i.e. server-side) development. And the question is not that easy as it may seem. The list of possible options becomes longer as the new technologies emerge. And if...

Rating — 5 (4 voices)
What are the stages of software testing in GBKSOFT

Development

The Guide to Software Testing Process

Some people thought that avoiding testing stage of the software development was a good idea. They thought it would save thier budget. How wrong they were…

Rating — 5 (1 voice)

Categories

All articles Business Company News Development Marketing StartUp App Ideas UI and Design

People are talking about

You've got

a project in mind

What's next?

Sent us a message with a brief description of your project.
Our expert team will review it and get back to you within one business day with free consultation and to discuss the next steps.

Testimonials

Jonathan
More good work from team GBKSOFT. All well executed. The support within GBKSOFT is excellent. Communication is good too, spoken English as well as written. Support
Devan
They write clean code, adhere to deadlines, and communicate extremely well. I strongly recommend anyone from the GBKSOFT agency and hope to work with them again myself. Clean Code
Garrett
They proved to be very good and they’re very reliable as well. They are quite conscientious. They will go the extra yard to make sure we're happy. Reliable
13
App Futura ExtractGood FirmsClutchAwwwards