Angular Unit Testing - aakash14goplani/FullStack GitHub Wiki

Topics Covered:
Fundamentals
Strings and Arrays
Setup and Tear down
Forms
Event Emitters
Spies
Interaction Testing
Confirmation Boxes
Limitations
Code Coverage


Fundamentals

  • The first thing you need to know is that tests are first class citizens, so all the practice as you have learned about writing clean and maintainable code applies to your tests as well.

  • Here are some examples:

    • Your functions or methods should be small preferably less than 10 lines of code.
    • They should have proper names and they should have a single responsibility.
    • You should test only one thing.
  • To run unit test you need to execute following command: ng test: this is going to build application and then it launches karma which is the test runner.

  • Example: a compute() function, a very simple function, to which if we give it a negative number it returns 0 otherwise it increments the number way 1.

  • Name of ts file: compute.ts, name of unit test file: compute.spec.ts. All our test files should have .spec.ts, this is the pattern that karma our test runner is looking for. Anytime we find files that match this pattern it looks at the tests in this files and runs those tests for us.

  • We use Jasmine as our testing framework which provides a bunch of functions that we use to write tests that two functions that we use most of the time are describe() and it(), we use describe() to define a suite which is a group of related tests and we use it() to define a spec or a test.

  • So here we are writing tests for the compute() function.

    export function compute(num: number) {
       if (num < 0) {
          return 0;
       }
       return num + 1;
    }
  • I'm going to call this compute(). Now the second argument here is a function that are test runner is going to call. Here we have one or more tests or specs to define a test. So this is the body of our test. This is what we're going to write and our test runner is going to call this function and then it will tell us if the test succeeds or not.

    describe('compute', () => {
       ...
    });
  • We need to test all execution paths, here we have two execution paths. One is for a negative number and the other is for a positive number. So we need to write two tests here.

  • First test here will be, It should return 0 if input is negative. Let's test this. So first I'm going to call it with -1 and get the result. Now we need to assert that this result is zero. To do that we use the expect() function that comes with Jasmine, so we expect this result to be zero.

    it('return 0 if negative input provided', () => {
       const result = compute(-1);
       expect(result).toBe(0);
    });
  • Now let's run this test. So when you run ng test this will launch a browser window connected to karma. Now here if you click this debug on and open chrome developer tools on the console tab you can see the list of all tests and their status. Here we have one test compute should return 0 if input is negative and you can see that this test is successful.

  • Second test here will be, increment number if positive input provided, the test name should increment the input if it is positive. Now I'm going to give it a positive number like 1 and we expect the result to be to save back here.

    it('increment number if positive input provided', () => {
       const result = compute(1);
       expect(result).toBe(2);
    });
  • This will be our final code for compute.spec.ts file

    describe('compute', () => {
       it('return 0 if negative input provided', () => {
          const result = compute(-1);
          expect(result).toBe(0);
       });
       it('increment number if positive input provided', () => {
          const result = compute(1);
          expect(result).toBe(2);
       });
    });

Strings and Arrays

Testing Strings

  • So a very simple function would give it a name and it returns "Welcome" plus that name.

    export function greet(name: string) {
       return 'Welcome ' + name;
    }
  • Now what are we going to test here - well we want to ensure that the name that we give to this function is in the outputs so it should include the name in the message or the output.

    describe('greet', () => {
       it('should return Welcome with string appended', () => {
          const variableName = 'Aakash';
          expect(greet(variableName)).toBe(variableName);
       });
    });
  • Now there is a problem with this test. This test is too specific. So if one day I come back here and I decide to add an exclamation mark here. This test is going to break. We don't want fragile tests that break often. So instead of checking for the exact message I'm going to check for the existence of my name in the output. So I'm going to replace this with toContain().

    expect(greet(variableName)).toContain(variableName);
  • Now this test is a little bit more general and if I change the message from Welcome to hi in the future this test will still pass the same principle applies when testing arrays.

Testing Arrays

  • So here we have getCurrencies(), a simple function that returns an array of three strings.

    export function getCurrencies() {
       return ['USD', 'INR', 'EUR'];
    }
  • If I want to write a test for this function I just want to assert that the result includes these items, but I don't care about their exact position because if in the future I decide to change the order of these items in this array and sort them alphabetically, I don't want my test to break my tests.

  • Now I'm going to expect this result to contain U.S. dollars, India Rupees or Euro. Order does not matter.

    describe('getCurrencies', () => {
       it('return length', () => {
          const currency = getCurrencies();
          const searchElemet = 'INR';
          expect(currency).toContain(searchElemet);
       });
    });

Setup and Tear down

  • We have vote component that has a property totalVotes and methods that modify the value of this property. The pattern we have here is state change. So in a lot of components we have methods that modify the state of the components.

    @Component({
       selector: 'app-vote',
       templateUrl: './vote.component.html',
       styleUrls: ['./vote.component.css']
    })
    export class VoteComponent {
       totalVotes = 0;
       voteChanged = new EventEmitter<number>();
    
       upVote() {
          this.totalVotes++;
          this.voteChanged.emit(this.totalVotes);
       }
    
       downVote() {
          this.totalVotes--;
       }
    }
  • Note that the name of our suite is VoteComponent, that's the system under test. Now let's write a couple of specs. So this VoteComponent should increment totalVotes when up voted.

  • So here I am going to create an instance of the VoteComponent, call the upVote() method and then expect that component that total votes to be 1.

    describe('VoteComponent', () => {
       let component: VoteComponent;
    
       it('should increment vote counter when upvoted', () => {
          component.upVote();
          expect(component.totalVotes).toBe(1);
       });
    });
  • This is how we test this method. Now this really is you see here represent a structure that you see in a lot of unit tests we call the structure Triple A which stands for Arrange-Act-Assert.

  • So the first line here is there any part where we initialize the system under test. In this case we are creating an instance of the vote component.

    let component: VoteComponent;
  • The second part is the act which often involves calling a method or a function.

    component.upVote();
  • And the third part is the assertion.

    expect(component.totalVotes).toBe(1);
  • Now let's write the second test. So it should decrement totalVotes went down voted

    it('should decrement vote counter when downvoted', () => {
      component.downVote();
      expect(component.totalVotes).toBe(-1);
    });
  • However there is a problem with this test. If you run this test the second one is going to fail because in the first one we're up voting. So the value of total votes is going to be 1. And this means in the second test the value of total votes is going to be zero not negative one.

  • So the problem we have here is that our tests have side effect the execution of one test can impact the execution of other tests. And with this our test will break quite often which is really painful. We don't want fragile tests remember. So how can we solve this problem.

  • These two tests these two tests have something in common - The initialization of our vote components and this initialization is only one line of code so it's not a big deal but sometimes when working with more complex objects the initialization may involve a few lines of code.

  • We can refactor these tests and move this initialization to a single place so we are not duplicating it in each test. The solution is to use the beforeEach() function. So in Jasmine We have another function called beforeEach() as the argument we pass a function here and our test runner is going to call this function before each test.

    describe('VoteComponent', () => {
       let component: VoteComponent;
    
       beforeEach(() => {
          component = new VoteComponent();
       });
    
       it('should increment vote counter when upvoted', () => {
          component.upVote();
          expect(component.totalVotes).toBe(1);
       });
    
       it('should decrement vote counter when downvoted', () => {
          component.downVote();
          expect(component.totalVotes).toBe(-1);
       });
    });
  • We also have afterEach() and it has the same signature. It takes a function that will be called after each test and this is a place where you do cleanup.

  • So in automated testing terms we refer to what we write in the beforeEach() function as the set up and what we write in the afterEach() function as the tear down.


Forms

  • Now let's take a look and an example of a form.

    export class FormsComponent {
       form: FormGroup;
       constructor() {
          this.form = new FormGroup({
             name: new FormControl(null, Validators.required),
             email: new FormControl(null, [Validators.required, Validators.email])
          });
       }
    }
  • Now what should we test here, well there are two things that we need to assert.

    • One is then when this component is initialized we'll have a form group with to form control objects and they should be called name and email because this is what our template expects.
    • The second test is around the validator for this name & email control. We want to ensure that this name & email fields or this name control is required.
  • Now the first test: form component should create a form with two controls. So we should expect this to be true or we can use another function here toBeTruthy().

    describe('FormsComponent', () => {
       let component: FormsComponent;
    
       beforeEach(async(() => {
          component = new FormsComponent();
       }));
    
       it('should create a form with two controls', () => {
          expect(component.form.contains('name')).toBeTruthy();
          expect(component.form.contains('email')).toBeTruthy();
       });
    });
  • Now for second test this component should make the name & email control required.

    it('should make name control required', () => {
       expect(component.form.get('name').setValue('')).toBeFalsy();
    });

Event Emitters

  • Let's take a look and an example of a component that uses an event emitters. We will reuse VoteComponent from last section

  • We have this property here voteChange which is an event emitter. So often we use that as an output property in angular components, but in this section we don't worry about this decorator because we're not working with templates so let's simplify the code. Now when we vote this component should raise an event called for change and in the event data we should have the total votes.

  • Let's test it - This component should raise voteChanged event when a voter. How do we do that. Well component that voteChanged, is an event emitter and even emitter are observables, so we can subscribe to them.

  • And here we can get the event that is raised in the event we have the total votes, so here we can add a function. Here we have a property called not.

    it('should emit an even when upvoted', () => {
       let totalVotes = -1;
    
       component.voteChanged.subscribe((voteCount) => {
          totalVotes = voteCount;
       });
       component.upVote();
    
       expect(component.totalVotes).not.toBeNull();
       expect(component.totalVotes).toBe(1);
    });

Spies

  • In this section we're going to take a look at an example of a component that uses a service to make calls to the backend. This is a simplified implementation wherein we fetch property values by calling the server and getting the list of to-do items.

  • So what should we test here. Let's see what's happening in this matter. You're calling service that getTodo() method which returns an observable & subscribes to the observable and then initialize the to-do's property. So in our unit test we want to call this method and then we want to assert that the two those properties initialized.

  • However you're not going to use this service here because the service is going to make calls to the backend and this is against a definition of a unit test because in unit tests we don't want to touch the file system or a database or call back on services. We want to isolate a component from external resources.

  • You test if you're going to give this component a fake service. This service is not going to make back on calls it's just going to return as simple observable.

02:14.460 --> 02:21.690 So here is our service and now this initialized our component new to Dewes component and pass the service

02:21.690 --> 02:22.210 here.

02:23.040 --> 02:27.510 Now there is also another approach in unit testing components that use services.

02:27.510 --> 02:33.510 So it's sort of giving this component a real instance of the to do service we give with a fake implementation

02:33.540 --> 02:35.640 which we call a stop.

02:35.880 --> 02:38.800 I'm going to show you how to do that in the next section.

02:38.920 --> 02:39.920 So here's our.

02:39.920 --> 02:43.710 Before each function nounless right to test.

02:44.030 --> 02:52.400 So this component should set to those property with the items returned from the server.

02:53.340 --> 02:53.570 All right.

02:53.580 --> 02:55.790 Now let's start with the range part.

02:55.890 --> 02:59.400 We want to change the implementation of to get to those.

02:59.940 --> 03:00.440 To do that.

03:00.450 --> 03:06.440 We use a function in jazzmen called Spy on with this function.

03:06.440 --> 03:09.540 We can put a spine on a method in a class.

03:09.860 --> 03:14.720 And we that spy we can check if that method has been called we can change the implementation of that

03:14.720 --> 03:15.590 method.

03:15.770 --> 03:19.890 We can return a different value or we can throw an error.

03:19.910 --> 03:24.910 So basically with us why we get control over a method in a class.

03:24.970 --> 03:29.160 Now here the first argument is the object we want to put a spy on.

03:29.290 --> 03:31.010 That is our service.

03:31.200 --> 03:34.830 And the second argument is the name of the method in that object.

03:34.830 --> 03:38.130 So get to those.

03:38.300 --> 03:47.990 Now Dot and call fake with this we can't change the implementation of get to those methods.

03:48.210 --> 03:50.490 Let's have a quick look at the implementation of this method.

03:52.320 --> 04:00.480 Look get to this is a method with no parameters that returns an observable so here we need to pass a

04:00.480 --> 04:06.240 function with the exact same signature that parameter let's Matha goes to.

04:06.500 --> 04:09.180 And here's the body of our fake method.

04:09.180 --> 04:12.550 So here we want to return an observable.

04:12.740 --> 04:22.730 Let's go on the top and import observable from X J.S. slice observable.

04:22.750 --> 04:32.720 I'm also going to import are actually yes and observable from with this we can create an observable

04:33.290 --> 04:35.030 from an array.

04:36.300 --> 04:41.880 Now here we need to simulate the response that is returned from the server the server will return an

04:41.940 --> 04:43.460 array of two items.

04:43.680 --> 04:50.190 So here we need to have another array that includes one or more to the items we can use simple numbers

04:50.190 --> 04:55.500 here and that's perfectly fine for this test because we're not going to test anything specific to two

04:55.530 --> 05:01.840 items or if you don't like this you can add real to the objects here.

05:02.310 --> 05:11.010 Id One title A and then duplicate and change accordingly.

05:12.020 --> 05:12.780 Like this.

05:12.910 --> 05:16.780 But this is going to add extra noise to our test and it does not add any value.

05:17.210 --> 05:19.950 So I would rather to revert this back to simple numbers.

05:20.580 --> 05:23.290 One two three.

05:23.300 --> 05:29.880 So with this when we call service that get to do this function it's going to be called.

05:30.140 --> 05:33.250 This is going to replace the real implementation.

05:33.250 --> 05:33.810 OK.

05:34.060 --> 05:36.150 So here's our arr. part.

05:36.250 --> 05:41.200 Now this act so a component energy in it.

05:41.680 --> 05:52.280 And now this asserts expect component to lose that length to be greater than zero.

05:52.290 --> 05:54.320 That's one way to write this expectation.

05:54.330 --> 05:56.190 It's a little bit more general.

05:56.430 --> 06:01.070 We can be a little bit more specific so we can write it like this.

06:02.030 --> 06:10.310 We expect the length to be three because we are returning exactly three different items from the server.

06:10.340 --> 06:13.190 We can also make it a little bit more specific.

06:13.190 --> 06:20.570 So we want to make sure that what we have here in this property is exactly what we get from the server.

06:20.580 --> 06:30.310 So here I can declare invaluable cut it to do and send it to this array that be returned from the server

06:35.830 --> 06:38.020 and then we can change our assertion.

06:38.170 --> 06:43.010 So we expect this to do is to be this array here.

06:43.840 --> 06:46.070 Let's test it ok.

06:46.100 --> 06:46.850 Beautiful.

06:46.910 --> 06:51.620 All our tests are passing now if the concept of spies is new to you.

06:51.620 --> 06:54.930 Don't worry you're going to look at more examples in the next lecture.


Interaction Testing

WEBVTT

00:02.180 --> 00:08.590 In the last lecture with test that energy and it method here now I'll just focus on the Add method.

00:09.910 --> 00:17.590 So here we create an object then we call service that add to add it to the server and then if the result

00:17.590 --> 00:24.630 is successful we add that object in the Tutu's property to do that array in this component.

00:24.700 --> 00:27.950 Otherwise you're going to display an error message.

00:28.030 --> 00:31.160 So here we need to write three tests.

00:31.210 --> 00:36.450 First we want to make sure that this component is going to call the server to save the changes.

00:36.700 --> 00:43.170 So we want to make sure that service that ad is called then we want to ensure that if the result is

00:43.170 --> 00:47.740 successful that the object is added in our property.

00:47.790 --> 00:48.340 And our.

00:48.390 --> 00:55.390 Ari And in the third Test we want to ensure that if the server returns on error we put that error in

00:55.390 --> 00:58.330 the message property.

00:58.350 --> 01:08.440 So let's go to our spec file first test this component should call the server to save the changes when

01:08.590 --> 01:11.280 new to the item is added.

01:15.020 --> 01:15.280 OK.

01:15.300 --> 01:19.360 Once again we're going to use ASPI because we don't want to really call the server.

01:19.710 --> 01:22.660 We just want to ensure that service the added cost.

01:23.040 --> 01:34.100 So spy on service the name of our method is at Aunt call fake.

01:34.100 --> 01:36.730 So we're going to replace the app method in our service.

01:37.040 --> 01:43.070 The new method here let's look at the implementation of that method the first.

01:43.110 --> 01:44.360 Here's our method.

01:44.430 --> 01:49.740 It takes it to the object and returns an observable.

01:49.750 --> 01:54.710 So in our error function you're going to get t as into goes to.

01:55.090 --> 01:57.780 And here's the body of our function.

01:57.790 --> 02:03.330 Now here once again we need to return an observable so return observable.

02:03.820 --> 02:08.590 We can't just call observable that empty because we don't really care about what is returned from the

02:08.590 --> 02:10.360 server in this test.

02:10.360 --> 02:14.990 We just want to ensure that the aftermath of our service is caught.

02:15.010 --> 02:24.200 Now we need to import this empty method on the top so duplicate this line and add empty here to our

02:24.310 --> 02:28.420 Yes and observable empty.

02:28.510 --> 02:29.900 So that was the arr. part.

02:30.190 --> 02:35.050 Now this act component DOD at.

02:35.170 --> 02:41.500 And finally the assertion we want to ensure that service that is called How can we do that.

02:41.590 --> 02:48.610 First we need to declare a variable here and set it to what is returned from spy on function

02:51.320 --> 02:56.800 expect spy to have been called.

02:56.930 --> 03:02.480 This is how we can test if a given method is called now the second test.

03:02.480 --> 03:11.100 So I'm going to select this test duplicate and change the test name.

03:11.160 --> 03:19.150 This component should add the new two returned from the server.

03:19.160 --> 03:23.390 So in this test we want to simulate it to do that is returned from the server.

03:23.390 --> 03:31.930 So instead of observable data MT-NW I'm going to use observable duck from an array.

03:31.960 --> 03:35.690 Now here the response from the server includes only one object.

03:35.690 --> 03:38.300 So let's simulate that.

03:38.360 --> 03:41.110 That's the idea is one.

03:41.160 --> 03:49.870 And just like the test in the last lecture we can extract this into a separate variable so let's do

03:51.740 --> 03:53.130 this.

03:53.170 --> 03:55.440 And then we can replace that here.

03:57.780 --> 03:58.060 All right.

03:58.070 --> 04:00.080 Now I want to change our expectation.

04:00.110 --> 04:05.390 We want to ensure that this to the object that is returned from the server is in our array.

04:05.510 --> 04:20.680 So expect component dot dot dot index I have to do to be greater than minus one.

04:20.700 --> 04:22.110 So this is our second test.

04:22.390 --> 04:27.780 Now there is actually another way to write this test that is a little bit cleaner and less noisy.

04:27.810 --> 04:35.590 So instead of using call fake here and defining an error function we can call return value.

04:36.720 --> 04:39.050 And then we can get this observable here.

04:40.930 --> 04:44.120 And simply pass it as an argument to this method.

04:46.570 --> 04:49.720 This way we don't need to define an error function.

04:49.880 --> 04:51.910 So it's a little bit cleaner.

04:51.950 --> 04:56.970 So this was the second test where the server returns a successful response.

04:56.990 --> 04:57.190 OK.

04:57.200 --> 05:03.620 Now the third test you want to ensure that if the server returns an error we put that error in the message

05:03.620 --> 05:04.940 property.

05:04.950 --> 05:15.680 So select duplicate changed the test name should set the message property.

05:16.290 --> 05:27.670 If server returns an error when adding in you to do so in this test we're not going to merge the two

05:27.680 --> 05:31.510 objects and we want to change this.

05:31.560 --> 05:38.850 So instead of creating an observable from an array you want to create an observable from an error so

05:38.850 --> 05:50.020 observable dot through once again we need to import this static method on the top so duplicate this

05:51.050 --> 05:55.400 and change this to throw.

05:55.430 --> 05:58.350 Now this method requires an error message.

05:58.420 --> 06:00.360 I'm going to declare that error here.

06:02.810 --> 06:04.500 Error from the server.

06:05.870 --> 06:07.890 And then pass it through.

06:11.310 --> 06:12.330 Now we act.

06:12.660 --> 06:23.290 And finally we expect that component that message to be this error here.

06:23.330 --> 06:25.550 Next we're going to write tests for the delete Matha.


Confirmation Boxes

WEBVTT

00:01.880 --> 00:06.880 So we have written three tests for that at metho or Tutu's component.

00:06.880 --> 00:14.230 Now let's move on to the last method delete here where displaying a confirmation box if the user confirms

00:14.780 --> 00:20.410 we should call the server to delete this to the item and if not the service should not be called.

00:20.410 --> 00:23.670 So when it do tests here are spec

00:26.490 --> 00:31.120 it should call the server to delete it to the item.

00:31.320 --> 00:33.180 If the user confirms

00:38.240 --> 00:39.270 now in this test.

00:39.410 --> 00:44.960 Apart from changing the implementation of our service we also want to change the implementation a window

00:45.370 --> 00:51.500 that confirm method because we don't want to display a confirmed box and running unit tests.

00:51.500 --> 01:01.810 So once again we put a spy on we know got confirmed method and return value.

01:02.790 --> 01:03.900 True.

01:03.960 --> 01:13.780 So if the user confirms we want to call the Sarah now our second spy is on our service so Service doc

01:13.780 --> 01:18.430 delete and return Valeo.

01:18.460 --> 01:22.780 I just want to return an empty observable because we don't really care about what is returned from the

01:22.780 --> 01:24.130 server.

01:24.130 --> 01:25.840 So observable doesn't empty

01:28.680 --> 01:30.120 that was the range part.

01:30.120 --> 01:35.000 Now this act component that Delete we get an idea here.

01:35.270 --> 01:37.710 Let's say one.

01:37.950 --> 01:43.330 And finally the assertion we want to ensure that the delete method of our service is caught.

01:43.560 --> 01:45.720 So I'm going to declare a variable here.

01:47.530 --> 01:53.630 And then expect spy to have been called.

01:53.700 --> 01:55.240 That's one way to write this test.

01:55.300 --> 01:56.590 It's a little bit general.

01:56.630 --> 01:58.630 You can make it a little bit more specific.

01:59.010 --> 02:05.040 I want to make sure that if I pass one here this value is going to the delete method of our service

02:05.070 --> 02:05.960 as well.

02:06.240 --> 02:15.190 So we can use to have been called with one so I want to make sure you're not accidentally having a different

02:15.250 --> 02:17.870 ID or service.

02:17.940 --> 02:19.370 So that was our first task.

02:19.590 --> 02:20.810 Now the second one.

02:21.270 --> 02:22.920 Let's duplicate this

02:26.040 --> 02:26.750 in this test.

02:26.850 --> 02:32.400 We want to make sure that if the user presses the canceled button and the confirmation box we are not

02:32.400 --> 02:35.080 going to call the server to delete that to die.

02:35.550 --> 02:41.660 So I'm going to change this text to shoot not in capital it makes it easier to read.

02:41.820 --> 02:50.030 Should not call the server to delete or to the item if the user cancels.

02:50.030 --> 03:00.590 Now here I'm going to change this to false and then change the expectation expect not to have being

03:00.890 --> 03:03.470 called OK.

03:04.070 --> 03:05.190 Let's test the result.

03:06.270 --> 03:06.930 Beautiful.

03:06.930 --> 03:08.210 All tests are passing.


Limitations

WEBVTT

00:02.370 --> 00:05.040 So in this section we have looks at various patterns.

00:05.040 --> 00:08.920 When you're testing our components we have looked at state changes.

00:09.000 --> 00:13.060 So we have methods that modify the value of one or more properties.

00:13.080 --> 00:16.970 And these are really easy to test as you have seen in this section.

00:17.030 --> 00:22.880 We also looked at forms events or Outwood properties and interaction with services.

00:23.330 --> 00:25.810 These are fairly easy to unit test.

00:25.910 --> 00:29.790 However there are a couple of limitations with unit tests.

00:29.960 --> 00:36.290 If your component is using a router it's not easy to unit test that you need to run that component in

00:36.290 --> 00:41.570 the angular environment which for this course I'm just referring to those kind of tests as integration

00:41.570 --> 00:47.590 tests even though you may argue that there are unit tests but irrespective of the terminology you cannot

00:47.660 --> 00:53.010 test those components with routers using the techniques you have learned in this section.

00:53.040 --> 00:56.650 Other limitation is around template bindings.

00:56.750 --> 01:03.080 So if it's a property in a component with these unit test we cannot ensure if that component renders

01:03.080 --> 01:05.360 that property or not.

01:05.360 --> 01:11.120 Similarly if we click on a button in the view we cannot ensure if the corresponding method in the component

01:11.150 --> 01:12.920 is called or not.

01:12.920 --> 01:18.170 So for these scenarios you're going to load a component in an angular environment so Angerer is going

01:18.170 --> 01:24.320 to compile the component with its template is going to inject the dependencies and then we can get that

01:24.320 --> 01:28.390 router and put a spy on it to change its implementation.

01:28.430 --> 01:30.460 And these are the topics for the next section.


Code Coverage

WEBVTT

00:02.450 --> 00:09.090 As you write test for our application we need to know how much of our code is covered with tests.

00:09.100 --> 00:17.910 So back in terminal when running in the test we're going to pass a parameter dash dash code dash coverage

00:19.360 --> 00:26.320 with this we get a new folder here coverage which gives us a report of how much of our code is under

00:26.330 --> 00:27.470 test.

00:27.490 --> 00:34.120 So let's open up this index that hd a million or browser and this is what we get.

00:34.320 --> 00:37.860 So I ended up you can see a summary of code coverage.

00:37.890 --> 00:45.290 So here we have 93 percent of the statements under test hundred percent of branches which means if an

00:45.330 --> 00:53.970 else blocks or execution paths 77 percent of the functions and 96 percent of lines of code and next

00:53.970 --> 00:59.990 to that we can see a more detailed number 79 lines out of eighty two lines of code are currently under

01:00.000 --> 01:01.100 test.

01:01.290 --> 01:07.950 Now below the summary can see a breakdown of code coverage based on the folders and files.

01:07.950 --> 01:09.760 So let me show you something.

01:10.010 --> 01:16.430 I'm going to go back to the tests and I wrote in The Last Lecture for our Tutu's component.

01:16.540 --> 01:19.140 I'm going to disable a couple of tests here.

01:19.450 --> 01:27.950 So the tests that we wrote for the delete method to disable the test you can put an X before the function.

01:28.000 --> 01:28.870 So that's one test.

01:28.870 --> 01:31.180 And here's the other test.

01:32.480 --> 01:40.200 You can also disable an entire suite where I didn't x before the described function.

01:40.230 --> 01:42.640 Now save now karma.

01:42.650 --> 01:47.480 We executed our tests and you can see two tests have been skipped.

01:49.370 --> 01:56.280 With this if you come back to this page and refresh look at the services folder.

01:56.360 --> 01:59.960 Now our code coverage here is reduced to 75 percent.

02:00.290 --> 02:01.540 Let's have a closer look.

02:03.420 --> 02:09.060 So here we have two files are to do service and are to do component into service.

02:09.060 --> 02:11.060 Our coverage is 60 percent.

02:11.100 --> 02:13.610 Let's have a look.

02:13.630 --> 02:19.180 So the lines that are highlighted with red are the lines that have no coverage in our tests which makes

02:19.180 --> 02:23.120 perfect sense because we haven't written any unit tests or the service.

02:23.140 --> 02:27.880 That's what we're going to do in the next section because in order to write test for the service we

02:27.880 --> 02:30.280 need to run this in the angular environment.

02:30.280 --> 02:36.420 Now let's get back let's look at our Tutu's component.

02:36.460 --> 02:40.770 Look we don't have any tests for the delayed Matha.

02:40.980 --> 02:45.660 So this is how you can track how much of a record is covered with tests.

02:45.690 --> 02:48.900 Now what is the ideal number for code coverage.

02:48.900 --> 02:51.100 Should we aim for 100 percent.

02:51.120 --> 02:52.130 Ideally yes.

02:52.200 --> 02:54.610 But that's really hard to meet and a lot of projects.

02:54.660 --> 02:59.100 And as I told you at the beginning of this section it really depends on the time and budget of your

02:59.100 --> 03:00.240 project.

03:00.480 --> 03:07.770 If you have enough time and budget for writing tests it's good to have at least 70 percent code coverage.

03:07.770 --> 03:14.280 Otherwise if you have limitations on constraints focus on the critical parts of your application right

03:14.280 --> 03:21.270 tests for methods with complex logic special methods with multiple execution paths that take longer

03:21.270 --> 03:23.090 to test manually.

03:23.190 --> 03:25.110 So that's all about code coverage.

03:25.170 --> 03:27.420 And this brings us to the end of the section.

03:27.630 --> 03:30.010 I hope you enjoyed that section and thank you for watching.

⚠️ **GitHub.com Fallback** ⚠️