More often than not I see Angular developers jumping through hoops trying to test the code in components. I see their tests full of spies, perfectly setting up the state of the component to hit certain lines, all in the name of “testing the code”. This cargo cult testing is the wrong way to go about things. Instead you want to forget about the code and start thinking about the user experience.
User experience, for a component? Yes. Angular developers often forget components manifest as HTML elements. This means they will have some effect on the browser and the user will most likely be able to interact with it. How the user sees and interacts with the component is what’s important. …
This is an abridged (and slightly opinionated) version of TypeScrip’s official handbook .
TLDR; Don’t trust code coverage metrics.
I usually start these posts with the use cases for the component or service. This time I’m going to start with an image:
Do you know how I got 100% coverage?
With a scaffold test file that only checks if Angular can create an instance of the component (generated by SimonTest). Now I wouldn’t say testing the component can load by itself is useless… but close.
If you’ve read any other of my articles you know where I’m going with this…
This is a great example of a component with 100% code coverage yet it only tests that it has a snowball’s chance in hell to load. This isn’t were you want to be so let’s actually test the component. …
TLDR: Use RxJS utility functions like
of to mock the observable dependencies. Start with the use cases for the component. Make your tests fail so you know you’re actually testing something.
As usual, let’s start with the use cases for the component. These are the things the user can do with the component. I keep harping on this topic because I often get asked for help either writing or testing a component; but when I ask for the use cases all I get is a description and a mockup of the component.
At that point I often send people back with “call me when you have the list of things the users can do with the component”. More often than not the mere act of writing down the list makes the problem go away. …
TLDR: Use test components sporadically so you can sleep better at night. Using it as the default test strategy makes your test files harder to read and maintain.
I often see test files with components declared just for the sake of testing. Except for very few cases, you don’t need it to get adequate coverage of your use cases (different than code coverage). Your code is already hard enough to maintain without creating extra artifacts to deal with.
The following example is small to make it easy to follow. The concept still applies for larger and more complex components. I have to say this because I often hear “my component is large/complex, I *need* to complicate things further in my tests”. This is similar to the rationalizations for adding boilerplate: “Yeah, it’s overkill for small projects, but it pays off on bigger ones”… No it doesn’t, the boilerplate just gets bigger. …
TLDR: Write tests against use cases, not implementations. Always make your tests fail to make sure they’re actually testing something.
Before writing the tests for the Hero Search Component, let’s start by listing the use cases for the component. These are the things the user can do with it. You write them down before writing the component (I hope) but in this case the component is already written.
Avoid State. Not that you should avoid it at all costs, but the same practices that lead to more state, are the same practices that makes your code harder to understand, extend, and refactor.
So in general, avoid the following:
Angular and similar frameworks are inherently stateful and OOP friendly, but that doesn’t mean we can’t move the needle a little bit towards the functional side. The goal isn’t to write 100% functional code (not even close). Instead I want to encourage you to adopt practices which use less state. …
As with every component and test you’ll ever write, it’s best to start with the list of things the component can do.
This is worth repeating. If you only get one thing out of this post, let it be this:
It’s much better to write and test a component starting from a list of things the user can do with the UI, rather than trying to test the code that powers it.
If you do your job right, you’ll either get 100% coverage or find blocks of code which aren’t really needed and thus can be deleted.
In our case the component is created already so we’ll skip that part. The component looks like…
TLDR; We got a test suite of 3K+ tests to run from over 5 mins down to 15 secs with the following optimizations:
I don’t know about you but every time I searched for ways to speed up Angular tests I’d always end up in some blog post telling me to run the tests in parallel. …
The dashboard component provides a good opportunity to reinforce the point that you should test what the component does, not how it does it.
RouterTestingModuleto be able to access the router links
getHeroesfrom hero service and make it return a set of hero-like objects.
Believe it or not the most important file is the HTML template because it contains the user interface and declares what the user sees and can interact with.
While we can be very specific in the things we want to test, it’s better to leave room for the template to change without affecting our tests. Here we probably want to test the following 3…