Subscribe to my email list now at http://jauyeung.net/subscribe/
Follow me on Twitter at https://twitter.com/AuMayeung
Many more articles at https://medium.com/@hohanga
By default, Angular tests run very slowly because a lot of dependencies are injected and components being tested are reloaded when each test isΒ run.
As a result, you get tests that take 30 minutes or more to run.
It is bad enough that an issue is opened on GitHub about it https://github.com/angular/angular/issues/12409.
To remedy this, we have to load all the dependencies only once when each test file is executed and then let the test run without reloading everything again.
We make a new spec file called spec-helper.spec.ts
and add the following:
export const beforeTest=()=> {
beforeAll((done)=> (async ()=> {
TestBed.resetTestingModule();
TestBed.configureTestingModule({
declarations: [
AppComponent,
LoginPageComponent,
MonitorPageComponent,
SettingsPageComponent,
AccountsPageComponent,
TopBarComponent,
SignUpPageComponent,
ImagesPageComponent,
AccountDialogComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
MatButtonModule,
MatCheckboxModule,
MatToolbarModule,
MatInputModule,
MatSidenavModule,
MatIconModule,
MatListModule,
MatTableModule,
MatDialogModule,
MatGridListModule,
RouterTestingModule.withRoutes(appRoutes),
FormsModule,
StoreModule.forRoot({
openSideNav: openSideNavReducer
}),
ClickOutsideModule,
HttpClientTestingModule,
CustomFormsModule
],
providers: [
UserService,
SecurityService,
AuthenticatedGuard,
{
provide: HTTP_INTERCEPTORS,
useClass: HttpReqInterceptor,
multi: true
},
{
provide: MatDialogRef,
useValue: {}
},
{
provide: MAT_DIALOG_DATA,
useValue: []
},
],
})
await TestBed.compileComponents();
// prevent Angular from resetting testing module
TestBed.resetTestingModule=()=> TestBed;
})().then(done).catch(done.fail));
}
given all these items exist in our code and libraries. The file will include all the dependencies and code in our Angular module.
Then we import the file in our specs and run the beforeTest
function that we exported.
After this, our unit tests will run orders of magnitude faster, from 30 minutes down to a few seconds.
Also, now we don't have to worry about including our dependencies in every test file and worry about missing dependencies for every test module.
Top comments (22)
The worst low performance issue occurs when components have external stylesheet and template files. For every test case, the compiler has to get access to, open and read two files per component, before it can even compile the component. So either use inline templates and styles or use the hack of preventing the Angular testing module from resetting between test cases.
Apparently, Ivy should make testing faster, but I haven't seen any facts about this yet.
If we just prevent the Angular testing module from resetting in beforeEach, we take care of the worst performance issue in tests and we don't have to add all declarables and dependencies to a single Angular testing module configuration which is hard to maintain and does not work well for all tests.
I used the hack with good results back in Angular version 5. I haven't tried it since then as I favor not using the TestBed at all for a lot of tests. One big caveat is that services and other dependencies are reused between test cases. So stateful service instances are not reset.
Do you know if using some of the testing libraries such as angular-testing-library or spectator help with this issue? I haven't used either of them, but am beginning to experiment. Angular Testing Library at least looks like it may expose components in a different way that gets around this issue.
I too have stopped using the TestBed for most tests and simply test components by treating them as simple classes and asserting against their public properties, but am beginning to look at these other libraries as an easier and quicker way to test against the DOM
Both of them wrap TestBed so they will have exactly the same problems. We did discuss adding ng-bullet to Spectator, but decided to wait for Ivy.
I have seen even after Ivy, ng-bullet is still helps in speed up the tests. Is the discussion still open?
I'm not sure. You're welcome to file an issue to Spectator.
Pretty much every Angular component have these files.
Honestly, It's like the Angular team didn't test it at all with lots of components in a module.
Are there any alternatives to that doesn't involve adding recreating the module in every file?
It's not only the speed, but having to recreate the module code for every test file is also a pain.
Oh, you mean having to setup all the needed Angular module imports and declarations? Are you aware of SCAMs?
One advantage is that you can often just import a component's SCAM to test it. It's so unexpectedly easy that Spectator had to put in a special option to undo some of its normal affordances to make component tests easier to set up.
I'm not aware of that. Too late for existing apps probably.
But looks useful for new apps.
I already refactored the TestBed to its own function so it can be imported and run anywhere, that's how I solved it.
Thanks. Of course, there's also the option to use shallow component tests, where we include no or only some view child components in our tests:
angular.io/guide/testing#nested-co...
But we still have to put dependencies in
declarations
right?Not with shallow components tests using
NO_ERRORS_SCHEMA
.That's great. It's annoying to have to put everything in the TestBed module.
Anything in Angular is more complex than the other frameworks.
Details on how Ivy will improve the performance issues discussed in this thread:
github.com/angular/angular/issues/...
Interesting solution! I noticed several people mentioning ng-bullet in the issue you linked. Have you tried that? I'm curious to know more about your experiences.
I looked at Stack Overflow and this is the only way I found.
I haven't tried ng-bullet. Did people say it's good?
Yes, it seemed to solve a lot of people's issues.
I have to check it out.
Thanks for finding that.
Details on what takes up the most time in Angular tests:
gist.github.com/Quramy/1dd5bed0bce...
Interesting...
More on this topic:
medium.com/angular-in-depth/angula...
"Next-level testing in Angular Ivy version 9" by yours truly
indepth.dev/next-level-testing-in-...
Thanks. That's a useful find.