In this section, you will learn the basics of writing a service test with NgVacuum. We provide sample code so you can follow along.
tl;dr: jump directly to the recap for the full code example.
Copy the code below if you would like to follow the examples in this section.
Instantiate the service
The first thing you'll need when testing a service is... the service itself!
Here, we would like to test
AccessControlService. We instantiate it with
The next thing you'll need is... nothing!
This is the only boilerplate needed to bootstrap a service test with NgVacuum.
All the dependencies of
AccessControlService are automatically mocked and injected. You don't need to deal with this yourself.
Write a test case
We would like to test that
checkAccess redirects to the logout page when trying to access the lobby while unauthenticated. This corresponds to the first branch of the method, specifically:
We start off by calling the method with the appropriate parameter and asserting the expected result.
This is what we get when running this test:
This error message tells us that something tried to access a member called
isAuthenticated on the service
AuthService, but we did not specify what should happen in this situation.
This error comes from OmniMock, the type-safe mocking library used by NgVacuum to mock all service dependencies. This library is a safer alternative to standard jasmine mocks, as it was built for TypeScript and it is type safe out of the box.
In this situation, a typical jasmine mock will not throw an error and instead it will allow the method to be called and return
undefined. This default behavior most likely violates the type contract of the class and can lead to difficult bugs down the line, such as the infamous
undefined is not a function.
Specify mock behavior
So how do we specify what happens when
AuthService.isAuthenticated is called?
We first need to obtain a reference to the mock of
getMock. Then we use the mock DSL provided by OmniMock to specify the behavior.
At this point, our test is still not passing. It complains that no behavior was specified for
Again, we use the DSL to specify what happens when this method is called.
But in this case we don't just want to specify what to do when this method is called. We want to verify that this method was called with the appropriate arguments.
We us the quantifier
.once() to specify that we expect this method to be called exactly once.
Inceed, this test fails when we remove the call in
In OmniMock, you need to invoke
verify() on a mock to verify that the number of calls match the expectation.
NgVacuum takes care of this automatically for you; It calls
verify() on all mocks in an
afterEach function, catching any missing call before the test finishes.
We wrote a true unit test for a service in complete isolation, with practically no boilerplate. What's more, the whole code is type-safe and won't break unexpectedly during future refactoring of the main code.
The complete test is shown below for reference.
The combo NgVacuum + OmniMock offers an extremely powerful mocking machinery which is able to mock just about anything; from methods to members, accessors and more. We cover some common use cases later in mocking techniques.
But first, let's take a look at how to mock a component.