Lessons: 67Length: 8.9 hours

Next lesson playing in 5 seconds

Cancel
  • Overview
  • Transcript

8.2 Unit Testing Services

In this lesson I'll show you how to add unit tests for one of the methods in the game service. I'll also explain how we can achieve basic test features like spying on methods to check they are called with the correct values.

1.Introduction
6 lessons, 42:00

1.1
Introduction
00:48

1.2
Get Started With Angular-CLI
11:09

1.3
Developing With Angular-CLI
13:17

1.4
TypeScript vs. JavaScript
06:54

1.5
Angular Modules From the CLI
04:31

1.6
CLI Options
05:21

2.Get Started With Angular
7 lessons, 42:38

2.1
Bootstrapping the Application
04:30

2.2
The Application Module
04:15

2.3
The Application Component
08:06

2.4
Component Styling
03:06

2.5
Global Styling
05:11

2.6
Creating a Component With the CLI
09:34

2.7
Creating a Service With the CLI
07:56

3.Core Concepts
7 lessons, 55:20

3.1
Component Trees
06:20

3.2
Dependency Injection
06:52

3.3
Content Projection
05:38

3.4
Component and Directive Lifecycle Methods
06:31

3.5
Component-Only Lifecycle Methods
05:28

3.6
Decorators
07:36

3.7
Models
16:55

4.Template Deep Dive
11 lessons, 1:10:56

4.1
Basic Data Binding With Interpolation
05:35

4.2
Property Bindings
07:07

4.3
Attribute Bindings
03:29

4.4
Event Bindings
08:16

4.5
Class and Style Bindings
05:44

4.6
The `NgClass` and `NgStyle` Directives
05:04

4.7
The `*ngIf` Directive
04:41

4.8
The `*ngFor` Directive
09:29

4.9
Inputs
05:33

4.10
Using Pipes in a Template
07:31

4.11
Using Pipes in a Class
08:27

5.Forms
10 lessons, 1:45:41

5.1
Handling User Input With Template Reference Variables
07:06

5.2
Template-Driven Forms
11:10

5.3
Template-Driven Forms: Validation and Submission
14:00

5.4
Reactive Forms
11:26

5.5
Using a `FormBuilder`
08:01

5.6
Reactive Validation With Built-in Validators
14:53

5.7
Creating Custom Validators for Template-Driven Forms
12:18

5.8
Creating Custom Validators for Reactive Forms
08:26

5.9
Observing Form State Changes
12:40

5.10
Working With the `@HostListener` Decorator
05:41

6.Routing
9 lessons, 1:15:10

6.1
Defining and Configuring Routes
07:53

6.2
Rendering Components With Router Outlets
10:14

6.3
Using Router Links for Navigation
05:25

6.4
Navigating Routes Using the Router
06:24

6.5
Determining the Active Route Using an Activated Route
07:16

6.6
Working With Route Parameters
10:42

6.7
Using Route Guards
07:36

6.8
Observing Router Events
10:55

6.9
Adding Child Routes
08:45

7.Using the HTTP Client
5 lessons, 56:24

7.1
Sending an HTTP Request
10:52

7.2
Handling an HTTP Response
11:22

7.3
Setting Request Headers
12:33

7.4
Intercepting Requests
09:04

7.5
Finishing the Example Application
12:33

8.Testing
10 lessons, 1:23:27

8.1
Service Unit Test Preparation
10:45

8.2
Unit Testing Services
13:24

8.3
Component Unit Test Preparation
12:35

8.4
Unit Testing Components
07:27

8.5
Unit Testing Component Templates
06:58

8.6
Unit Testing Pipes
04:41

8.7
Unit Testing Directives
04:56

8.8
Unit Testing Validators
04:48

8.9
Unit Testing Observables
11:37

8.10
Unit Testing HTTP Interceptors
06:16

9.Building for Production
1 lesson, 03:40

9.1
Building for Production
03:40

10.Conclusion
1 lesson, 01:32

10.1
Conclusion
01:32


8.2 Unit Testing Services

Hi folks. In this lesson, we're going to see how we can unit test our services. We got the spec file for the game service into a state where it runs, in the last lesson. So now, we can start to add our own tests to the file. So, I like to add a describe for each public method in the file. So let's add one for the startGame method. Now we can test, what the method actually does by adding its inside this describe. So one thing the method does is create a new deck and save it, in the deck property of the game service. So this should be super easy to test. First of all, let's just make sure there's nothing hanging around in the deck property of the game service. Now let's invoke the start game method. And now let's check that the deck property is defined. And let's see if the test is passing. And we can see, that it is. So, I've set the test up in a very specific way. I've got three individual lines of code that I've separated with line breaks. And the reason why I've done this is because unit tests should follow a pattern known as the AAA pattern. Each test should be broken into sections which arrange the conditions for the test, that's the first A, act, that's the second A, and finally make an assertion, which is the third A. So triple A tests, I've divided my tests up into different sections. The first one is the arrange section, so in order to arrange the conditions for this test. The only thing that we need to do is delete the deck property if it already exists. So then we can act and in order to act, all we need to do is invoke the method that's being tested. In this case, that's the start game method. And lastly we make an assertion. And we do that using Jasmine's expect method, so the thing that we expect is the deck property and what we are expecting is that that is defined. So we use a matcher, which is a special method of Jasmine code to be defined. And that just tests that the thing that we want to assert is defined. And the test is passing. So we know that it is defined. So we know that the start game method does create a new deck, awesome. Another thing the start game method does is use the transform method of the pipe on the cards inside the deck using the face cards pipe. We can also test this, but it will be slightly more complicated. So let's add it, a new it for this test. So it, is a Jasmin method by the way just like describe is. And let's just make the window slightly wider so that we can actually see what's going on without this whole full down breaking it. So what we need to do is watch the transform method of the pipe and make sure that it gets called. So as well as the global describe and it methods that we making new soft. Jasmine also add, say global function called spion and we can use that to watch methods. In order to check that they get called and see what parameters they get passed. There is a special place that we should add spies however. We shouldn't add spies inside a test, so we shouldn't add them just in an it method, and we definitely shouldn't add them in a describe. So what we need to do is add them using another global function called before each, and this will get invoked by Jasmine before each test. So, let's add it to the start game describe. We don't want to add it to the outer describe with the other before each methods, because then it will get evoked before every single test in this whole file. We don't want to do that. We just want to spy on the pipe within the tests for this start game method. So we can add to put 4H, to the nesting describe and it will only get evoked for the methods inside this describe. So the Spy On method takes two arguments. The first is the object which contains the method that we want to spy on. So in this case, that's the pipe. And then the second argument is the name of the method that we want to spy on in string form. So the method that we're gonna be spying on is the transform method, which all pipes have. So when we add a spy, Jasmine will basically wrap the method that we're spying on, and this will cause the method not to be called. But in our case, we do want the method to be called. Because we store the return of the transform method in the cards property of the deck. So, in order to get Jasmine to actually invoke the method that's being spied on, we just need to call through to the original method And we can do that using the call through method, which we chain onto the N method. So there's a number different methods that we can do here. We don't always have to call through, sometimes we might want to call a Different method, a fake method. And in that case we use, an doc cool fake, instead. But in this case we just want to call through to the original method. So now we need to invoke the start game method once again and check whether the transform method gets called. So the transform method itself has two arguments, which we can see on the left hand side of the screen here. The first argument that gets passed Is the cards, which is an array and the second argument is the easy mode property of the game service. So first of all let's set easy mode to true. And now we can invoke the start game. And now we can invoke the start game method. And now let's check that the transform method was called. So the first argument is an array, at this point we don't necessarily we don't care what is in that array. So we can just check that any array was passed as the first argument. And we set the easy made property to true, so true should have been passed as the second argument. So the test is structured in the same way, we've got three distinct sections. We've got an arranged section, which in this case we just set the easy mode property to true. We then got an act section, where again we're just invoking the start game method. Which is the method under test. And lastly we make an assertion and that's the transform method of the pipe, was called with an array and the value of true. So let's go back to the browser now, which should still be running in the background. And we can see that all second test this past, excellent. So what else do the start game method do? Well, it calls the shuffle and deal methods of the deck. Testing these presents a challenge, because we can't spy on the methods. In each test for the start game method, we want to invoke the method, that's the whole point. And each time we invoke the method, a new instance of the deck is created. So if we were to try and spy on methods of the deck, those spies would be lost each time we invoked the start game method. What we need to do instead is test indirectly for other things that they affect. So the deck starts out in order with all of the spades in order and then all of the hearts in order and then all of the diamonds in order. And lastly, all of the clubs in order. So to test the shuffle method has been called, we can just check that the deck is not in this order. Let's import our own instance of the deck into the test. And then we can compare the deck in the game service with a fresh instance of the deck that we've just imported. So we can't just compare the two arrays because arrays are different instances of objects. And so they will never equal and so the test would always pass if we just compared the game service.deck.cards to the freshdeck.cards. So what we can do instead is stringify each of the arrays of cards and just check that the strings aren't equal. So we've saved the test, so the test should have rerun in the background, let's go back to the browser now and see if our test is passed. And we can see that it has, so we know the deck is being shuffled as it should be. This should be fine for our needs, so what now? Well the start game deals cards to both players. So again, this gives us an easy way to indirectly test that the deal method does get called. So we first create, two new players. We then invoke the start game method, and we then assert that each player's hand Is two in length. Let's go back to the test browser once again. And we can see tha'st all four tests are now passing. And, we can see that the new test is passing also. So lastly, the start game method sets the game started property to true. This should be incredibly easy to test. So we first set the game started property to false explicitly, we then call the start game method. And we can then check that the game started property is equal to true. And let's just check the output, and we can see that test passes also, perfect. So now the start game method is completely tested. So what I would like you to do now is carry on and write some additional tests for the player turn, dealer turn, and reset game methods. You should be able to fully test each of those using only the things we've looked at in this lesson. Feel free to leave the get number fact method for now though. We'll come back and see how to test observable based code later on. Just remember to take that f off the outer describe when you're done. Otherwise, these tests will also run when you try to f describe other files. So in this lesson we saw how to unit test a service. We saw how to get a reference to the service being tested using the inject method, to get Angular to initialize the service correctly for us with it's dependency injection. And we saw how we can write basic unit tests using Jasmine to test the things that the method does internally. Thanks for watching.

Back to the top