5

This is my before each block for unit testing. It works great, making a new component instance available for each test. However, it takes approx 4 secs to execute the beforeEach block. When you've got 200 tests, that is slow!

I want to move the bulk of the code to a beforeAll block (which works if you use the Jasmine done() callback instead of using async) but I still am unable to create a new instance for each test. Some tests fail because the sole instance has been tampered with by previous tests.

How do I ...

  1. Create a new component instance without executing this time consuming code for EVERY test.

or

  1. Reset the instance to its untampered with state.
beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [AppModule],
      providers: [{provide: APP_BASE_HREF, useValue: '/'},
        MockBackend,
        BaseRequestOptions,
        {
          provide: Http,
          useFactory: (pBackend: MockBackend, pOptions: BaseRequestOptions) => {
            return new Http(pBackend, pOptions);
          },
          deps: [MockBackend, BaseRequestOptions]
        }]
    }).compileComponents()
      .then(() => {
        fix = TestBed.createComponent(Route1DetailComponent);
        instance = fix.componentInstance;
        injector = fix.debugElement.injector;
      });
}));
halfer
  • 19,824
  • 17
  • 99
  • 186
danday74
  • 52,471
  • 49
  • 232
  • 283
  • 3
    Maybe `AppModule` is the problem. Try it with just adding what is actually needed for the test. Personally, I never use AppModule for my unit tests. I try to keep all the outside variables minimal when unit testing. – Paul Samsotha Oct 20 '16 at 14:21
  • 1
    It depends on why exactly it takes so long. But the thing about unit testing and modules is that only the module that current unit belongs to should be bootstrapped. – Estus Flask Oct 20 '16 at 14:34
  • +1 to both of you thanks, I understand and agree that my approach could be better - but I am still not happy that you have to re-load all imports again to get a new instance of an already loaded component, doesn't seem right to me – danday74 Oct 20 '16 at 14:48
  • This is the purpose of unit tests. Previous tests shouldn't have a chance to affect current tests, but this is exactly what happens if you replace `beforeEach` with `beforeAll`. – Estus Flask Oct 20 '16 at 15:01
  • 1
    FYI, the reason the `beforeAll` won't work is that the angular testing infrastructure resets the `TestBed` using a global `beforeEach`; you can see that it's registered [here](https://github.com/angular/angular/blob/2.1.1/modules/%40angular/core/testing/testing.ts#L23-L28). – cartant Oct 21 '16 at 14:20

2 Answers2

1

I decided to adopt the approach suggested by @peeskillet and @estus in the comments. Thank you both.

Determining which components / modules to include became my next problem which was addressed here ..

How do you know which components to import when unit testing?

Community
  • 1
  • 1
danday74
  • 52,471
  • 49
  • 232
  • 283
1

I wrote a little function to precompile everything for given modules to be re-used in each test. By default Angular recompiles everything each time, but this sets them up as if they were compiled using AoT at the beginning of your test suite. It is the precompileForTests() function in s-ng-dev-utils. Check it out - I hope it helps!

Eric Simonton
  • 5,702
  • 2
  • 37
  • 54