Introduction to Angular Testing

Isolated, Shallow, Integrated, and End to end testing. What is it and when do you use it?

In Angular, we have a lot of different types of testing. I can imagine that you have many questions when you see them. I had that question so I went into a deep dive to make it all clear. At the end of this post, I hope this all makes sense for you as well.

divider-byrayray.png

Test tooling for Angular

In Angular, we use a few different tools to set up automated testing.

If you have created the Angular project with the CLI and didn’t say it should ignore the testing then the testing capabilities of the CLI are set up for you.

By default, the Angular CLI sets Jasmin as our testing framework and Karma as our test runner. But if you want to make use of Jest or another testing framework, you are free to do so.

divider-byrayray.png

Types of Testing in Angular

In Angular, we have 4 different main types of testing.

  • Isolated unit testing
  • Shallow unit testing
  • Integration testing
  • End to end testing

divider-byrayray.png

Isolated unit testing

A unit might contain business logic that needs to be tested in isolation.

There are a few Angular units that can be tested in isolation.

  • Pipe
  • Service
  • Class
  • Component
  • Directives

In isolation we always should mock our dependencies, otherwise, it isn’t isolation anymore.

import { FormComponent } from './my-form.component'

describe('NgqFormComponent', () => {  
    let component: FormComponent  
    let mockApiService

    beforeEach(() => {  
        mockApiService = jasmine.createSpyObj([  
            'logout',  
            'init',  
            'getApiJson',  
            'getCurrentRoute',  
            // add morehere  
        ])

        component = new FormComponent(mockApiService)  
    })

    it('should be defined', () => {  
        expect(component).toBeDefined()  
    })  
})

For example, the FormComponent has a dependency on the apiService. So we mock it with a createSpyObj from Jasmine, which makes a mock service with all the public methods that our real service has.

Thanks to this method we can also test if a certain method is being called. When need to overwrite a method, we can do that too.

In isolated unit testing, we don’t test the template parts for a component, only the logic behind it. In this test, we test all the methods that have the expected behavior.

divider-byrayray.png

Shallow unit testing

With shallow unit testing, we test a component with a template, but we ignore the rendering of child components. By passing NO_ERRORS_SCHEMA into our configuration, we can achieve this. Otherwise, you will get a lot of errors.

beforeEach(async(() => {

  TestBed.configureTestingModule({  
   declarations: [  
    FormComponent,  
  ],  
   imports: [  
    BrowserModule,  
   ],  
  ],  
  schemas: [NO_ERRORS_SCHEMA]  
  })  
  .compileComponents();  
 }));

divider-byrayray.png

Integration testing

With integration testing, we test how 2 or more components work with each other. We can do this when components are depending on each other.

When you want to test more components together, you import them via the testing module.

beforeEach(async(() => {

  const todo1 = new TODOItem('Buy milk', 'Remember to buy milk');  
  todo1.completed = true;  
  const todoList = [  
   todo1,  
   new TODOItem('Buy flowers', 'Remember to buy flowers'),  
  ];

  TestBed.configureTestingModule({  
   declarations: [  
    AppComponent,  
    NavbarComponent,  
    TodoListComponent,  
    TodoItemComponent,  
    FooterComponent,  
    AddTodoComponent,  
    TodoListCompletedComponent,  
  ],  
   imports: [  
    BrowserModule,  
    NgbModule.forRoot(),  
    FormsModule,  
    appRouterModule  
   ],  
   providers: [  
    {provide: APP_BASE_HREF, useValue : completedTodoPath },  
    {  
     provide: TodoListService,  
     useValue: {  
      todoList: todoList  
     }  
    }  
   ]  
  })  
  .compileComponents();  
}));

divider-byrayray.png

End-to-end testing

With end-to-end testing, we test pieces of the application in a working application. We can test the working combination of the frontend and backend.

For this type of testing, we can use Selenium, Protractor, Cypress, Webdriver.io.

End-to-end testing is also a good way to test the differences in different browsers across multiple devices. There are multiple services which help you set this up in your CI/CD.

divider-byrayray.png

Conclusion

We learned which types of testing there are in Angular and when to use one. For me, this makes so much sense right now.

If you have questions about some of the testing possibilities in Angular, please let me know in the comments. I will do my best to help you further 👍

In the end, we all need some help from others. So don’t be shy! Just ask 😉

Happy Coding 🚀

Thanks!

hashnode-footer.png I hope you learned something new or are inspired to create something new after reading this story! 🤗 If so, consider subscribing via email (scroll to the top of this page) or follow me here on Hashnode.

Did you know that you can create a Developer blog like this one, yourself? It's entirely for free. 👍💰🎉🥳🔥

If I left you with questions or something to say as a response, scroll down and type me a message. Please send me a DM on Twitter @DevByRayRay when you want to keep it private. My DM's are always open 😁

Did you find this article valuable?

Support Dev By RayRay by becoming a sponsor. Any amount is appreciated!