Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Angular testing hygiene

Angular testing hygiene

Piotr Lewandowski

March 25, 2021
Tweet

More Decks by Piotr Lewandowski

Other Decks in Programming

Transcript

  1. Piotr Lewandowski
    Good testing hygiene
    Piotr Lewandowski

    View Slide

  2. piotrl.net 2
    • JavaScript tes-ng is great, but not bullet proof
    • When the app scales, some prac-ces needs to
    be adjusted
    Lighiting Talk – 15min
    3 #ps for today

    View Slide

  3. 3
    piotrl.net
    Testing Modules

    View Slide

  4. piotrl.net 4
    What testing modules do we know?
    • HttpClientTestingModule
    • RouterTestingModule
    • BrowserTestingModule
    • NoopAnimationsModule
    Goal?
    • Avoid imperative mocking
    • Deliver predefined mocks and used modules
    • Cut Dependency Injection tree
    @NgModule({
    providers: [
    IconRegistryMock,
    {
    provide: IconRegistry,
    useExisting: IconRegistryMock,
    },
    ],
    })
    export class IconTestingModule {
    }
    @Injectable()
    export class IconRegistryMock {
    getIcon(name: string): Observable {
    return of('');
    }
    }

    View Slide

  5. piotrl.net 5
    Configurable testing modules?
    TestBed.configureTestingModule({
    imports: [
    FeatureFlagsTestingModule.with({
    angularEnabled: true,
    }),
    ],
    });
    Especially useful for
    Shared services
    Shared direc2ves

    View Slide

  6. piotrl.net 6
    Configurable testing modules?
    @NgModule()
    export class FeatureFlagsTestingModule {
    static with(config) {
    return {
    ngModule: FeatureFlagsTestingModule,
    providers: [
    {
    provide: FeatureFlagsService,
    useFactory: () => new FeatureFlagsServiceMock(config),
    },
    ],
    };
    }
    }

    View Slide

  7. 7
    piotrl.net
    Shallow testing
    but when?

    View Slide

  8. piotrl.net 8
    What is shallow testing?

    {{ someCode | json }}


    {{ someCode | json }}

    page-xyz.component.html
    huge component
    WHAT IF?
    Our page have 100 huge
    components
    And their children have
    100 huge components
    And so on ...
    schemas: [NO_ERRORS_SCHEMA],

    View Slide

  9. piotrl.net 9
    When? Testing huge components
    page-xyz.component.spec.ts
    TestBed.configureTestingModule(
    {
    declarations: [
    ComponentWeTest,
    MockOfChildComponent1,
    MockOfChildComponent2,
    MockOfChildComponent3, // and so on for up to
    MockOfChildComponent4, // 10, 20 mocked child components
    MockOfChildComponent5,
    MockOfChildComponent6,
    ],
    imports: [
    YourModuleWrappingAllDependenciesForAllModules,
    ButtonComponentModule, // + other design components
    DependentModule1,
    DependentModule2,
    DependentModule3,
    DependentModule4, // and so on for up to
    DependentModule1, // 10, 20 imported modules
    ],
    })
    EFFECT
    Single test suite 20s+
    Modified shared direc2ve = broken
    test
    Dependency mess. Hard to maintain.

    View Slide

  10. piotrl.net 10
    Apply shallow testing
    page-xyz.component.spec.ts
    TestBed.configureTestingModule({
    schemas: [NO_ERRORS_SCHEMA],
    declarations: [
    ComponentWeTest,
    ],
    imports: [
    // only TestingModules
    // for direct dependencies of ComponentWeTest
    ],
    providers: [
    // only mocks for direct dependencies of ComponentWeTest
    // or mocks that we modify for test behaviour
    ],
    });
    EFFECT
    Single test suite 200ms
    Modified shared directive
    = not affecting test
    Truly unit test. No maintanance effort
    Cannot do integra2on tes2ng

    View Slide

  11. 11
    piotrl.net
    avoid done()
    together with real asynchronousity

    View Slide

  12. 12
    When do we deal with asynchronous code in tests?
    • async/await
    • async functions
    • waitForAsync()
    • observables with done()
    Avoid all in tests:
    • Race condi-ons
    • Slow tests because we’re wai-ng for real events
    • Always green tests if we’re not careful

    View Slide

  13. 13
    Async with done()
    is it really bad?
    better approach?
    Rx marbles
    fakeAsync()
    it('should refresh after 1s', (done) => {
    // given
    // when
    serviceWithTimeout().subscribe((el) {
    // then
    expect(el).toBeTruthy();
    done();
    });
    });

    View Slide

  14. 14
    RxJs and fakeAsync()
    it('should be green for async', fakeAsync(() => {
    // given
    const result = [];
    // when
    interval(1000).subscribe((el) => result.push(el));
    tick(2000);
    // then
    expect(result).toEqual([0, 1]);
    }));
    fakeAsync() > waitForAsync()
    piotrl.net

    View Slide

  15. piotrl.net 15
    Questions?

    View Slide