Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Bearded JavaScripter
Bearded JavaScripter

Posted on • Edited on

     

TDD in Angular - Understanding an Angular Unit Test

In myprevious post, I talked about the Basics of General Testing. It was a short introduction into the different types of testing and how to approach testing in Jasmine.

In this article, I want to take a look at the auto-generated unit test files of an Angular Application and explain what's happening. I'll unit test services for my examples since it's a good place to start understanding the fundamentals. Also, Angular Components have a bit more going on under the hood and that requires an article of its own.

Many Angular developers get confused and even overwhelmed by what's happening in a.spec.ts file. This article will change that.

Code for this article can be foundhere.

Angular Services

Services are by far the easiest to unit test. They're simply Injectable classes that may or may not have some state and contain a collection of functions. However, they shouldn't be taken lightly.Your services are where all your business logic should be. Therefore, testing them as much as you can will prove useful.

Let's take a look at an InventoryService and its auto-generated.spec.ts file:

There's a few points to note here.

There's adescribe block that groups all our tests together for this service. A variable calledservice is also initialized.

ThebeforeEach block contains code that is run before every single unit test in this spec file. It helps us have a clean slate before running each test so that previous tests don't interfere. This helps with the essence of unit testing (testing one thing in isolation without any external factors).
There are other blocks of code like this to help us maintain clean tests, namelybeforeAll,afterEach andafterAll. You can read more about them and more pretty cool testing tools in theJasmine Global API.

Looking inside thebeforeEach block, we see 2 unfamiliar pieces of code.TestBed.configureTestingModule creates a dummy module for us to work with.TestBed.inject initializes our service and injects it into that dummy module. This holds true for components, pipes, guards, etc. This is the unit testing philosophy combined with Angular's architecture.

An Angular application must have at least one module so a dummy module is created with only the piece of code being tested (in this case, the service) and nothing else. This way, nothing else from the outside can interfere with the tests. Pure Isolation.

Eachit block of code is a unit test.it is a function that accepts 2 arguments: A string describing the test and a function that must contain anexpect assertion function. Thisexpect function is what Jasmine runs to assert expected values against actual results.

it('should be created'), () => {...} is a unit test that is always created for any component, pipe, service, etc. It doesn't make sense looking at other unit tests if we can't initialize our code in the first place.

Building our Service

Let's say that I wanted to add some code to track the number of items in my inventory and a way to increment and decrement the amount.

Remember! We're approaching this from a TDD standpoint. We can write empty placeholders and then Tests first!

We write tests for what we want our code to do and then consider other cases. Tests for main functionality should look something like this:

You'll notice I usedfdescribe as opposed todescribe. This means "Focused Describe" and Jasmine will only run this suite of tests instead of all tests in the Application.

When we run our unit tests, we'll notice some failures (as expected).

Alt Text

It's telling us that the "should increment the count" and "should decrement the count" tests are failing. This is expected since we didn't write any code in there as yet. Let's change that.

And now our tests are passing:

Alt Text

The more astute among you might have realized that our decrement function isn't finished. We shouldn't be able to decrement if theinventoryCount is already 0.

A reasonable test for this can be:

it('should not decrement when count is 0',()=>{expect(service.inventoryCount).toBe(0);service.decrementCount();expect(service.inventoryCount).toBe(0);});
Enter fullscreen modeExit fullscreen mode

Re-running the tests gives us:

Alt Text

Our function currently decrements whatever value is stored in the service. We want it to decrement only when the value isn't 0. This is also a simple way to make sure thatinventoryCount never falls below 0 (assuming you want your system like that).

We can modify the function to be:

decrementCount(){if(this.inventoryCount===0)return;this.inventoryCount--;}
Enter fullscreen modeExit fullscreen mode

Now our tests are passing again.

Alt Text

Conclusion

In this article, we covered the following:

  • The basic structure of an Angular Unit Test
  • What happens in thebeforeEach block
  • Why a dummy module is necessary for testing
  • Building an Angular Service using TDD

There are a lot more of these articles to come where we'll dive deeper into services, mocking, component life cycles, etc. Stay tuned for more and thanks a bunch for reading! 😄

Top comments(1)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
spideep profile image
Alexis Rengifo
  • Joined

On decrementCount() if the inventoryCount is 0 you return nothing. For which cases to throwing an error could be more convenient?

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Full Stack Web Developer interested in readable, maintainable, composable software. Constantly (L)earning. Your code is a reflection of yourself.
  • Location
    Trinidad and Tobago
  • Joined

More fromBearded JavaScripter

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp