Repository navigation
Description
I'm submitting a ... (check one with "x")
[ ] bug report
[x] feature request
[ ] support request
Current behavior
Importing modules into TestBed.configureTestingModule can slow tests down substantially. We have a 'shared module' with parts, that lots of our components use, including a third party library or two. It is very convenient to import this module as a rather than cherry pick in the tests, however testing a small component yesterday, I saw test bootstrap taking two whole seconds and had to cherry-pick dependencies to make tests run reliably.
Expected behavior
TestBed.configureTestingModule should be performant.
Minimal reproduction of the problem with instructions
In this plunker
- go to the
src/simple.spec.tsand comment and un-comment theSharedModuleimport intoconfigureTestingModule. - Observe time it takes for test to run.
I am seeing a jump from 0.079s to 0.241s. (~= 3x slower). Multiply that by 5 cases and this simple test takes a whole second. Make the shared module larger and you have real problems.
What is the motivation / use case for changing the behavior?
- Slow tests hurt TDD workflow
- Slow enough tests disconnect karma from the browser and fail the suite.
Please tell us about your environment:
Win10, VsCode, Webpack,
-
Angular version: 2.0.X
Yes.
-
Browser: Locally, PhantomJS. Plunk tested in Chrome.
-
Language: TypeScript (though tests are transpiled to ES5 prior to running, naturally)
Note: Even as I write this, I wonder if it's a reasonable expectation for large modules to go through TestBed quickly? Maybe I'm just doing something wrong architecturally, (use multiple, smaller shared modules, not one big one, etc.) However, tests are time-consuming enough without having to track down every individual dependency of a more complex component just to get started.
Activity
ollwenjones commentedon Oct 28, 2016
Seems like the goal is really to have a fresh component instance each time, and for the most part the testing module is going to be static for a particular .spec file. It also seems like configuring the module at each iteration is the part that is really adding on the time. A better pattern could be configuring the module once, then
testModule.createComponentmultiple times.TestBed.configureTestingModuleonce and callingTestBed.createComponenton that module multiple times doesn't work, though... maybe I'm missing an obvious way to preserve module state between iterations?Edit: FWIW I tried logging the timestamp and it looks like most of the time passes during
TestBed.createComponent, notTestBed.configureTestingModule- however I still suspect it's related to module configuration, since adding things to imported modules adds to the time, whether or not those imports are used in the component being tested.vmandy commentedon Nov 15, 2016
I have a noticed unit test execution performance issues that seem directly related to this issue.
I have an ionic 2 / angular 2 app. When trying to unit test my components using TestBed and ComponentFixture classes, there is easily 1-2 seconds spent in the setup of each test that seems directly related to the
imports: [IonicModule.forRoot(MyComponent)]that I've added to my testing module via theTestBed.configureTestingModule({...})method.When I remove the import, my tests run much faster, but they obviously fail because my component's template no longer compiles.
ollwenjones commentedon Nov 15, 2016
@vmandy I've been working around this by doing one or more of:
All of which are time consuming and sub-optimal 👎 (except from the point of view that I am really forced to isolate the unit I am testing?)
It seems like there are some theoretical optimizations to this at least, because I know these components are not taking 1-2 secs to bootstrap at run-time.
FlemmingBehrend commentedon Dec 1, 2016
Iam having similar problems. Thought it was caused by wallaby, but it seems to be the TestBed.
wallabyjs/public#885
mlakmal commentedon Dec 15, 2016
I am seeing the same issue. Any unit test with component compilation is taking close to 1sec...
ollwenjones commentedon Dec 15, 2016
Unfortunately I was pulled off the Angular 2 project and haven't looked at this in quite some time. It seems like a lot of the complications of TestBed (test-module setup, generally, not just performance) could be avoided by an approach similar to the enzyme.shallow render approach in the React ecosystem. - where just one unit is rendered and none of it's dependencies - the same thing can be accomplished by over-riding an Angular component's template in the .spec, but that is often tedious/time-consuming as well.
mlakmal commentedon Dec 15, 2016
we have close to 2000 test cases getting executed just under 1 min in Angular 1 where Angular 2 takes 1min to execute just 100 test cases. It would be nice if we can get a resolution for this issue as it hinders the testing capabilities in large applications.
ollwenjones commentedon Dec 15, 2016
@mlakmal I think there are lots of folks relying heavily on e2e tests, or just testing functional logic in component classes
Which doesn't test any of the template rendering (template logic)... but it does allow easy testing of class logic at least
mlakmal commentedon Dec 15, 2016
@ollwenjones thanks, i am going to try that out. i really doesn't want to test any template logic since most of that gets covered by our automated tests, so just testing the component class code should be enough.
ollwenjones commentedon Dec 15, 2016
@mlakmal sweet! Makes me happy to contribute something that actually helps someone. 🍻 - FWIW I'm often torn about template-rendering unit tests, because it's so easy to slip into testing the framework.
michaelbromley commentedon Dec 15, 2016
I'm in the process of upgrading a pretty big project from rc.4 to 2.3, so it's the first time we're using the NgModule approach.
We have ~1000 unit tests, with maybe 1/2 of those testing components. Prior to upgrade, tests run pretty quickly - around 30s.
After upgrade, they take at leat twice as long, but the worst thing is that they seem kind of "flaky" - Karma will periodically lost the connection to Chrome and often I will need to refresh Chrome multiple times. I suspect that something is timing out but haven't isolated it yet.
@ollwenjones regarding "shallow" component tests, did you know about the
NO_ERRORS_SCHEMAthat you can set in the testing module?This means that the compiler just ignores any elements it does not recognize, meaning you do not need to declare all the components used in the template of the component under test.
marclaval commentedon Dec 15, 2016
Found the same issue in Angular's tests: #13500
I was able to improve the situation by creating bespoke testing modules for each test.
ollwenjones commentedon Dec 15, 2016
@michaelbromley 😮 I had no idea about
NO_ERRORS_SCHEMAwould have / will probably save me hours - also an opportunity to hopefully speed up some of these tests, as the leaner the test-module the faster TestBed seems to go.95 remaining items
Goodwine commentedon Dec 4, 2019
@MatMercer
Be aware that angular versions are only supported for a limited amount of time [docs]
And also, if the Angular team improves the test setup performance like you want, it would be on a
newer version, so you would have to upgrade anyways, there's really not workaround*.
On another Issue about something similar, someone mentioned that the next Angular release with Ivy and R3SomethingTestBed made test setup run much faster even without AOT.
angular/angular-cli#6650
git diff HEAD^ --name-onlyand process the data to generate something that you can pass toconst context = require.context(...in thetest.tsfile, but that means you have to be regenerating the HTML file every time (which I was doing using a gulp task watching changes for TS/HTML files)(Disclaimer: I'm not a member of Angular team)
MatMercer commentedon Dec 4, 2019
I'm currently refactoring my component tests (49 files) to use
ng-bulletthat I've added manually from here into my project as @giniedp said. The snippet @giniedp gave is a little bit outdated so I'm giving a warning to the newcomers: use the ng-bullet from here, it's updated and worked with my angular 5.2.0.@Goodwine Indeed, what you have said is right, if they will give performance improvements in the next releases there is no "workarounds", we will need to upgrade it anyway.
After I finish the refactor I'll share the results here, I'll probably use
karma-paralleltoo.giniedp commentedon Dec 4, 2019
it is actually the very same implementation as the latest version of ng-bullet, except that i choose to skip
await TestBed.compileComponents().MatMercer commentedon Dec 4, 2019
@giniedp
The signature of your snippet that gave me compilation errors:
The signature of the
ng-bulletproject:Probably the way we used them in our tests is different (I'm using based in the
ng-bulletnpm page), that's why your snippet didn't worked for me.giniedp commentedon Dec 4, 2019
you are right. That is another minor difference in how we adopted from ng-bullet. The change on your side would have been
for us it was important not to take away the flow control from the developer, so he is still able to do async stuff inside
configureTestSuiteMatMercer commentedon Dec 4, 2019
@giniedp @Goodwine
That's interesting @giniedp. In my use-case we don't care about the flow control.
I have to say thanks! I successfully added
ng-bulletin the project and the tests execution went from 5m:30s to 30s. The problem I had with the peer dependencies before was because mynodeversion was too outdated.Adding karma-parallel didn't did much (28s instead of 30s) and broke a test so I didn't used it.
Quramy commentedon Dec 5, 2019
@Goodwine
Yes.
enabledIvy: true(it's tsconfig.json's option, see https://angular.io/guide/ivy#opting-into-angular-ivy) configures to useTestBedRender3as the TestBed implementation. It's TestBed for Render 3, a.k.a. Ivy. And Ivy JiT compiler has caching mechanism for compiled modules and components. ( See https://github.com/angular/angular/blob/8.2.14/packages/core/src/render3/jit/module.ts#L49-L66 ).So if you turn Ivy on,
TestBed.configureTestingModule(...).compileComponents()gets faster because the second or later compilation for the same components are skipped.JoostK commentedon Mar 15, 2020
With Ivy, the
TestBedinfrastructure has been overhauled and no longer requires recompilation of testing modules. I have seen significant speedups (8x) in tests because of this change.krokofant commentedon Mar 15, 2020
@JoostK Good to hear!
Would nice to have an overview of the performance differences between:
AndrewKushnir commentedon May 29, 2020
Hello everyone,
As @JoostK mentioned, Ivy TestBed was overhauled to avoid unnecessary recompilations between tests, which helped improve overall performance. We did some measurements to compare ViewEngine and Ivy TestBed versions using Material Components test suite, Angular.io app and Angular Framework unit tests - performance improvement was around 30-40%. We also received feedback from developers that they see even better results on their projects.
I’m closing this ticket and feel free to create new ones if you notice TestBed performance issues after switching to Ivy.
Thank you.
angular-automatic-lock-bot commentedon Jun 30, 2020
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
This action has been performed automatically by a bot.